%!PS-Adobe-2.0
%
% Copyright (C) 2001-2012 Artifex Software, Inc.
% All Rights Reserved.
%
% This software is provided AS-IS with no warranty, either express or
% implied.
%
% This software is distributed under license and may not be copied,
% modified or distributed except as expressly authorized under the terms
% of the license contained in the file LICENSE in this distribution.
%
% Refer to licensing information at http://www.artifex.com or contact
% Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
% CA  94903, U.S.A., +1(415)492-9861, for further information.
%

% $Id: opdfread.ps 11951 2010-12-15 08:22:58Z ken $
% pdfread.ps - A procset for interpreting an ordered PDF 1.3 file.

% This module defines routines for interpreting a PDF file with
% a Postscript interpreter. To convert a PDF file into Postscript
% just pre-contcatenate this file. The PDF file must satisfy
% few constraints :
%
% 1. It must contain only Postscript level 2 objects encoded with
% the PDF 1.3 language. Higher PDF levels must be re-distilled
% with CompatibilityLevel=1.3 .
%
% 2. Objects must be ordered so that any resource be defined before
% its usage.
%
% 3. The PDF file must not include other PDF files.
% Consequently we have a single instance of the PDF reader.
% We use this fact to simplify binding of the routines.
%
% 4. The PDF root object must always have the object id 1.
%
% 5. Generations besides 0 are not allowed.
%
% 6. xref must appear after all objects.
%
% Assuming the currentfile isn't positionable.
% As a consequence, the reader fully ignores xref.

% ====================== Error handler =======================
% A general error handler prints an error to page.

%
% See if our notification from ps2write is present. If it is
% then pick it up. Otherwise define it as false. Used to prevent
% use of setmatrix at start of each page. The DSC-compliant
% output from ps2write wraps pages in a save/restore, so we don't
% need the setmatrix, and it breaks use of psnup with the output.
%
currentdict /DSC_OPDFREAD known {
  currentdict /DSC_OPDFREAD get
}{
  false
} ifelse

10 dict begin % A dictionary for local binding

% This switch used to control paeg independent values, like
% whether to use InitialMatrix in SetupPageView
%
/DSC_OPDFREAD exch def

/this currentdict def
/y 720 def
/ebuf 200 string def

/prnt {
  36 //this /y get moveto //ebuf cvs show
  //this /y 2 copy get 12 sub put
} bind def

/newline {
  36 //this /y get moveto
  //this /y 2 copy get 12 sub put
} bind def

errordict /handleerror
{ systemdict begin
  $error begin
  newerror
  { (%%[ Error handled by opdfread.ps : ) print errorname //ebuf cvs print (; OffendingCommand: )
    print /command load //ebuf cvs print ( ]%%) = flush
    /newerror false store vmstatus pop pop 0 ne
    { grestoreall
    } if
    errorname (VMerror) ne
    { showpage
    } if
    initgraphics
    0 720 moveto
    errorname (VMerror) eq
    { //this /ehsave known
      { clear //this /ehsave get restore 2 vmreclaim
      } if
      vmstatus exch pop exch pop
    }
    /Courier 12 selectfont
    {
      (ERROR: ) //prnt exec errorname //prnt exec
      (OFFENDING COMMAND: ) //prnt exec
      /command load //prnt exec
      $error /ostack known {
        (%%[STACK:) =
        (STACK:) //prnt exec
        $error /ostack get aload length {
          //newline exec
          dup mark eq {
            (-mark-) dup = show
          } {
            dup type /nametype eq {
              dup xcheck not {
                (/) show
                (/) print
             } if
          } if
          dup = //ebuf cvs show
          } ifelse
        } repeat
      } if
    } ifelse
    (%%]%) =
    //systemdict /showpage get exec
    quit
  } if
  end
  end
} bind readonly put

end % A dictionary for local binding


50 dict begin

% ===================== Debugging =========================================

/DefaultSwitch  % <name> DefaultSwitch -
{
  dup where {
    pop pop
  } {
    false def
  } ifelse
} bind def

/=string 256 string def

/=only {
  //=string cvs print
} bind def

/HexDigits (0123456789ABCDEF) readonly def

%% This routine assumes that a PostScript int is only 32 bits
%% we partially address that by and'ing 15 with the 4 bits of
%% data in order to ensure that we don't index off the end of
%% the string above. However, if the integer is genuinely
%% more than 32 bits we still only print the first 32.
/PrintHex  % <int> PrintHex -
{ 8 {
    dup -28 bitshift 15 and //HexDigits exch 1 getinterval //=only exec
    4 bitshift
  } repeat
  pop
} bind def

/PDFR_DEBUG DefaultSwitch
/PDFR_DUMP DefaultSwitch
/PDFR_STREAM DefaultSwitch
/TTFDEBUG DefaultSwitch
/RotatePages DefaultSwitch
/FitPages DefaultSwitch
/CenterPages DefaultSwitch
/SetPageSize DefaultSwitch

/error  %  mark <object> .... error -
{ % A stub for a while.
  counttomark 1 sub -1 0 {
    index dup type /arraytype eq { == } { =only } ifelse
  } for
  () =
  cleartomark
  % Assuming ....Undefined is never defined.
  % Use it to emit an error.
  ....Undefined
} bind def

//SetPageSize {
  //RotatePages //FitPages or //CenterPages or{
    mark (/RotatePages, /FitPages and CenterPages are not allowed with /SetPageSize) //error exec
  } if
}
{
  //FitPages //CenterPages and {
    mark (CenterPages is not allowed with /FitPages) //error exec
  } if
}
ifelse

% ===================== Utilities =========================================

/knownget % <dict> <key> knownget <value> true
          % <dict> <key> knownget false
{
  2 copy known {
    get true
  } {
    pop pop false
  } ifelse
} bind def

/IsUpper  % <int> IsUpper <bool>
{ dup (A) 0 get ge exch (Z) 0 get le and
} bind def

% Copy (recursive) packedarray|array to to global VM
% NOTE: a packedarray will be converted to non-packed (too bad)
/cpa2g {	% <packedarray|array> cpa2g <packedarray|array>
  dup length array	% <src> <dest>
  0 1 2 index length 1 sub {
        % <src> <dest> index
    dup 3 index exch get cp2g
        % <src> <dest> index <globalelement>
    3 copy put pop pop
  } for
  exch pop
} bind def

% Copy (recursive) dict to to global VM
/cpd2g {
  dup length dict exch {
    cp2g 2 index 3 1 roll put
  } forall
} bind def

% Copy string to to global VM
/cps2g {	% <string> cps2g <string>
  dup length string copy
} bind def

/cp2gprocs
<< /arraytype //cpa2g /dicttype //cpd2g /packedarraytype //cpa2g /stringtype //cps2g >>
def

/cp2g {		% <any> cp2g <any>
                % where <any> is array | dict | string | packedarray
                % NOTE: The object must be readable (not executeonly or noaccess)
  dup gcheck not {
    dup //cp2gprocs 1 index type
    2 copy known {
      get currentglobal 3 1 roll true setglobal exec exch setglobal
      % set the attributes appropriately (we must have 'read' access to get this far)
      1 index wcheck not { readonly } if
      1 index xcheck { cvx } if
      exch pop		% discard original (local) object
    } {
      pop pop	% discard type
    } ifelse
  } if
} bind def

% ===================== Work Data =========================================

/BlockBuffer 65535 string def % Make it big to load entire TrueType font
/PDFReader currentdict def
/ObjectRegistryMaxLength 50000 def
/ObjectRegistry 10 dict def
ObjectRegistry
begin
  0 ObjectRegistryMaxLength dict def
end
/CurrentObject null def
/DoneDocumentStructure false def
/GraphicState 20 dict begin
  /InitialTextMatrix matrix def
  /InitialMatrix matrix currentmatrix def
currentdict end def
/TempMatrix matrix def
/GraphicStateStack 20 array def
/GraphicStateStackPointer 0 def
/InitialTextMatrixStack 20 array def
/InitialTextMatrixStackPointer 0 def
/PDFColorSpaces 50 dict def
/InstalledFonts 50 dict def
/MacRomanEncodingInverse null def

% We need some structures in local VM, put then into the userdict :
currentglobal false setglobal
userdict /PDFR_InitialGS gstate put
userdict /PDFR_Patterns 50 dict put
userdict /FuncDataReader 10 dict put
setglobal

% ===================== Constants =========================================

% The ExtGState elements are composite, thus need to be copied to
% global VM (in case they aren't already global).
/InitialExtGState 20 dict begin
  /BG2 currentblackgeneration cp2g def
  /UCR2 currentundercolorremoval cp2g def
  /TR2 currentglobal false setglobal [ currentcolortransfer ] exch setglobal cp2g def
  /HT currenthalftone cp2g def
currentdict end readonly def

/InitialGraphicState 20 dict begin
  /FontSize 0 def
  /CharacterSpacing 0 def
  /TextLeading 0 def
  /TextRenderingMode 0 def
  /WordSpacing 0 def
currentdict end readonly def

/SimpleColorSpaceNames 15 dict begin
  /DeviceGray true def
  /DeviceRGB true def
  /DeviceCMYK true def
currentdict end readonly def

/1_24_bitshift_1_sub 1 24 bitshift 1 sub def

/ReadFontProcs 10 dict def % Will be filled below.

/GetObject % <id> GetObject obj true
           % <id> GetObject false
{
  dup ObjectRegistryMaxLength idiv
  //PDFReader /ObjectRegistry get exch knownget {
    exch knownget
  } {
    pop false
  }ifelse
} bind def

/PutObject % <id> <obj> PutObject
{
  1 index ObjectRegistryMaxLength idiv   %  id obj oregnr
  //PDFReader /ObjectRegistry get 1 index knownget {
            % object already defined in Objectregistry
                                                        % id obj oregnr dict
            exch pop                                    % id obj dict
            3 1 roll put
  }{
           % object not already defined in ObjectRegistry
                                                        % id obj oregnr
           //PDFReader /ObjectRegistry get dup
           begin    					% new Objectregistry entry:
           1 index ObjectRegistryMaxLength dict def
           end
           exch get      % id obj dict
           3 1 roll put
  }ifelse
} bind def

% ===================== Reading PDF objects ===============================

/Register % <DefaultDaemon> <id> <obj> Register -
{
  1 index GetObject {
                                                                % d id obj e
      dup xcheck {
         4 3 roll pop    					%  id obj e
         //PDFR_DEBUG {
           (Have a daemon for ) print 2 index ==
         } if
         %% We've got a definition daamon, execute it:
         exec
      } {
         dup null ne {
             mark (The object ) 4 index (is already defined : ) 4 index //error exec
         } {
           pop             					% d id obj
         } ifelse
         3 2 roll        					% id obj d
         %% Execute the default Daemon
         exec
      }ifelse
  } {
                                                                % d id obj
   3 2 roll              					% id obj d
   exec                  					% execute the default deamon
  }ifelse
  PutObject
} bind def

/IsRegistered % <id> GetRegistered <bool>
{
  GetObject {
    null ne
  } {
    false
  }ifelse
} bind def

/GetRegistered % <id> GetRegistered <obj>
{
  dup GetObject not {
    exch mark exch (Object ) exch ( isn't defined before needed (1).) //error exec
  } if
  % id obj
  dup xcheck {
    exch mark exch (Object ) exch ( isn't defined before needed (2).) //error exec
  } {
    dup null eq {
      exch mark exch (Object ) exch ( isn't defined before needed (3).) //error exec
    } if
    exch pop                                            % e
  } ifelse
} bind def

/StandardFontNames <<
  /Times-Roman true
  /Helvetica true
  /Courier true
  /Symbol true
  /Times-Bold true
  /Helvetica-Bold true
  /Courier-Bold true
  /ZapfDingbats true
  /Times-Italic true
  /Helvetica-Oblique true
  /Courier-Oblique true
  /Times-BoldItalic true
  /Helvetica-BoldOblique true
  /Courier-BoldOblique true
>> def

/CleanAllResources % - CleanAllResources  -
{ //PDFR_DEBUG {
    (CleanAllResources beg) =
  } if
  //PDFReader /ObjectRegistry get {
    dup length 0 exch 1 exch 1 sub {                     % R i
      2 copy get dup xcheck {
      % Don't clean a daemon.
        pop pop
      } {
        dup null eq {
          pop pop
        } {
          dup type /dicttype eq { /.Global known } { pop false } ifelse {
            pop
          } {
            //PDFR_DEBUG {
              (Dropping ) print dup =
            } if
            1 index exch /DroppedObject put
          } ifelse
        } ifelse
      } ifelse
    } for
    pop
  }forall  % Check each dictionary in the ObjectRegistry
  FontDirectory length dict begin
  FontDirectory {
    pop
    dup //StandardFontNames exch known not {
      dup null def
    } if
    pop
  } forall
  currentdict
  end {
    pop
    //PDFR_DEBUG {
       (Undefining font ) print dup =
    } if
    undefinefont
  } forall
  //PDFR_DEBUG {
    (CleanAllResources end) =
  } if
} bind def

/PrintReference % <array> PrintReference <array>
{
  //PDFR_DEBUG {
    ({ ) print
    dup {
      =only ( ) print
    } forall
    ( }) =
  } if
} bind def

/R % <id> <gen> R <daemon>
{ % Make a reference daemon.
  0 ne {
    exch mark exch (A referred object generation ) exch ( isn't 0.) //error exec
  } if                                                  % id
  [ % <id> proc <obj>
    exch //GetRegistered /exec load
  ] cvx
  //PrintReference exec
} bind def

/IsObjRef %  <any> IsObjRef <bool>
{
  dup type /arraytype eq {
    dup length 3 eq {
      dup xcheck exch
      dup 0 get type /integertype eq 3 2 roll and exch
      dup 1 get //GetRegistered eq 3 2 roll and exch
      2 get /exec load eq and
    } {
      pop false
    } ifelse
  } {
    pop false
  } ifelse
} bind def

/DoNothing
{
} def

/RunTypeDaemon  % <id> <obj> RunTypeDaemon <id> <obj>
{
  dup type /dicttype eq {
    dup /Type //knownget exec {
      //PDFReader /TypeDaemons get exch
      //knownget exec {
        exec
      } if
    } if
  } if
} bind def

/obj % <id> <generation> obj <id>
{
  //PDFR_DEBUG {
    (Defining ) print 1 index =only ( ) print dup =only ( obj) =
  } if
  0 ne {
    exch mark exch (An object generation ) exch ( isn't 0.) //error exec
  } if
} bind def

/endobj  % <id> <obj> endobj -
{
  //PDFR_DEBUG {
    (endobj ) =
  } if
  count 1 eq {
    pop
  }{
    dup type /dicttype eq {
      dup /.endobj_daemon //knownget exec {
        //PDFR_DEBUG { (.endobj_daemon for ) print 2 index = } if
        exec
      } if
    } if
    dup type /dicttype eq { dup /ImmediateExec known } { false } ifelse {
      pop pop
    } {
      //PDFR_DEBUG {
        (Storing ) print 1 index =
      } if
      //RunTypeDaemon exec
      //DoNothing 3 1 roll //Register exec
    } ifelse
  }ifelse
} bind def

/StoreBlock % <buf> StoreBlock -
{ % Stores a (encoded) stream data block to the current object.
  //PDFR_DEBUG {
    (StoreBlock ) print //PDFReader /BlockCount get =only (, Length = ) print dup length =
  } if
  dup length string copy
  //PDFReader /BlockCount get exch                      % i s
  //PDFReader /CurrentObject get 3 1 roll               % o i s
  put                                                   %
  //PDFReader /BlockCount get 1 add
  //PDFReader exch /BlockCount exch put
} bind def

/CheckLength % <val> CheckNumber <val>
{ dup type /integertype ne {
    mark (Object length isn't an integer.) //error exec
  } if
} bind def

/ResolveD % <dict> <key> <check> ResolveD <value>
{
  3 copy pop get                                        % <> key {} e
  dup //IsObjRef exec {
    % We've got a reference daemon, execute it :
    //PDFR_DEBUG {
      (Resolving ) print //PrintReference exec
    } if
    exec                                                % <> key {} val
    exch exec                                           % <> key val
  } {
    exch pop
  } ifelse
  dup 4 1 roll                                          % val <> key val
  put                                                   % val
} bind def

/ResolveA   % <array> <index> <check> ResolveA <value>
{ 2 index 2 index get
  dup //IsObjRef exec {
    exec
    exch exec
    3 copy put
  } {
    exch pop
  } ifelse
  exch pop exch pop
} bind def

/StoreStream  % <id> <obj> StoreStream <id> <obj>
{ % Stores a (encoded) data stream copy to the current object.
  dup //PDFReader exch /CurrentObject exch put          % id obj
  //PDFReader /BlockCount 0 put
  dup /Length //CheckLength //ResolveD exec             % id obj l
  //PDFR_DEBUG {
    (StoreStream Length = ) print dup =
  } if
  currentfile exch () /SubFileDecode filter             % id obj file
  { dup //BlockBuffer readstring {                      % id obj file buf
      //StoreBlock exec
    } {
      //StoreBlock exec
      exit
    } ifelse                                            % id obj file
  } loop
  pop                                                   % id obj
  //PDFReader /CurrentObject null put
  //PDFR_DEBUG {
    (StoreStream end.) =
  } if
} bind def

/MakeStreamDumper % <file> MakeStreamDumper <file>
{ % Debug purpose only.
  //PDFR_DEBUG {
    (MakeStreamDumper beg.) =
  } if
  currentglobal exch dup gcheck setglobal
  [ exch                      % f
    1 dict dup /c 0 put exch  % d f
    1024 string               % d f s
    { readstring pop          % d s
      (StreamDumper ) print 1 index /c get =string cvs print ( ) print
      dup length =string cvs print ( <) print dup print (>\n) print
      dup length              % d s l
      3 2 roll                % s l d
      dup /c get              % s l d c
      3 2 roll                % s d c l
      add /c exch put         % s
    } /exec load
  ]
  cvx 0 () /SubFileDecode filter
  exch setglobal
  //PDFR_DEBUG {
    (MakeStreamDumper end.) =
  } if
} bind def

/ShortFilterNames 15 dict begin
  /AHx /ASCIIHexDecode def
  /A85 /ASCII85Decode def
  /LZW /LZWDecode def
  /Fl  /FlateDecode def
  /RL  /RunLengthDecode def
  /CCF /CCITTFaxDecode def
  /DCT /DCTDecode def
currentdict end readonly def

/AppendFilters  % <file> <dict> AppendFilters <file>
{
  //PDFR_DEBUG {
    (AppendFilters beg.) =
  } if
  dup 3 1 roll                                      % d f d
  /Filter //knownget exec {                         % d f F
    dup type /nametype eq {                         % d f /F
      dup //ShortFilterNames exch //knownget exec {
        exch pop
      } if
      2 index /DecodeParms //knownget exec {        % d f p /F
        exch
      } if
      filter                                        % d f'
    } {                                             % d f []
      dup 0 exch 1 exch length 1 sub {              % d f [] i
        2 copy get                                  % d f [] i /F
        dup //ShortFilterNames exch //knownget exec {
          exch pop
        } if
        3 1 roll                                    % d f /F [] i
        4 index /DecodeParms //knownget exec {      % d f /F [] i DP
          exch get                                  % d f /F [] dp
        } {                                         % d f /F [] i
          pop null                                  % d f /F [] dp
        } ifelse
        dup null eq {                               % d f /F [] dp
          pop 3 1 roll filter exch                  % d f' []
        } {                                         % d f /F [] dp
          3 1 roll                                  % d f dp /F []
          4 1 roll filter exch                      % d f' []
        } ifelse
      } for
      pop                                           % d f'
    } ifelse
    //PDFR_DEBUG //PDFR_DUMP and  {
      //MakeStreamDumper exec
    } if
  } if
  exch pop
  //PDFR_DEBUG {
    (AppendFilters end.) =
  } if
} bind def

/ExecuteStream  % <id> <obj> ExecuteStream <id> <obj>
{ % Executes a (encoded) data stream.
  dup //PDFReader exch /CurrentObject exch put          % id obj
  dup /Length //CheckLength //ResolveD exec             % id obj l
  //PDFR_DEBUG {
    (ExecuteStream id = ) print 2 index =only ( Length = ) print dup =
  } if
  //PDFReader /InitialGraphicState get
  //PDFReader /GraphicState get copy pop
  //PDFReader /Operators get begin
  % currentfile exch () /SubFileDecode filter           % id obj file
  % We would like to use the code above,
  % but HP LaserJet 1320 continues parsing after the byte count exceeds.
  pop currentfile 0 (endstream) /SubFileDecode filter   % id obj file
  1 index //AppendFilters exec
  cvx mark exch                                         % id obj mark file
  exec
  counttomark 0 ne {
    mark (Data left on ostack after an immediate stream execution.) //error exec
  } if
  cleartomark                                           % id obj
  end % Operators
  //PDFR_DEBUG {
    (ExecuteStream end.) =
  } if
  //PDFReader /CurrentObject null put
  dup /IsPage known {
    dup /Context get /NumCopies //knownget exec {
      1 sub {
        copypage
      } repeat
    } if
    EPS2Write not {showpage} if
  } if
} bind def

/stream  % <id> <obj> stream <id> <obj>
{
  //PDFR_DEBUG {
    1 index =only ( stream) =
  } if                                                  % id obj
  % Run the object definition daemon, if exists :
  1 index GetObject {
                                                    % id obj e
    dup xcheck {
      exec
      % Disable the daemon :
      1 index null PutObject
    } {
      pop
    } ifelse
  }if
  dup /ImmediateExec known {
    dup /GlobalExec //knownget exec {
      currentglobal 4 1 roll
      setglobal
      //ExecuteStream exec
      3 2 roll setglobal
    } {
      //ExecuteStream exec
    } ifelse
  } {
    //StoreStream exec
  } ifelse
  dup /.CleanResources //knownget exec {
    /All eq {
      //CleanAllResources exec
    } if
  } if
} bind def

/HookFont % <id> <obj> <font_descriptor> HookFont <id> <obj>
{
    //PDFR_DEBUG {
      (Loaded the font ) print dup /FontName get =
    } if
    {
      dup /FontFileType get dup /Type1 eq exch /MMType1 eq or {  % id obj fd
        % We assume that the Type 1 font has same name with no prefix
        % due to pdfwrite specifics.
        % We use it to find the font after it is defined.
        % We could redefine 'definefont' for hooking the font,
        % but we don't think that it could be guaranteedly portable :
        % a 3d party PS interpreter may set a special context
        % when running the font file.
        % Note that this mechanizm does not depend on the
        % font name uniquity, because the last 'definefont'
        % is only important.
        dup /FontName get                               % id obj fd fn
        //PDFReader /RemoveFontNamePrefix get exec
        findfont                                        % id obj fd g f
        exit
      } if
      dup /FontFileType get /TrueType eq {              % id obj fd
        //PDFReader /MakeType42 get exec
        //PDFR_DEBUG {
          (Font dict <<) =
          dup {
            1 index /sfnts eq {
              exch pop
              (/sfnts [) print
              {
                (-string\() print length //=only exec (\)- ) =
              } forall
              (]) =
            } {
              exch //=only exec ( ) print ==
            } ifelse
          } forall
          (>>) =
        } if
        dup /FontName get exch definefont
        exit
      } if
      mark (FontHook has no proc for ) 2 index /FontFileType get //error exec
    } loop
    /Font exch put                                      % id obj
} bind def

/endstream % <id> <obj> endstream <id> <obj>
{
} bind def

/xref % - xref -
{
  //PDFR_DEBUG {
    (xref) =
    //PDFR_DUMP {
      //PDFReader /ObjectRegistry get ==
    } if
  } if
  end % The procset
  count 0 ne {
    mark (Excessive data on estack at the end of the interpretation.) //error exec
  } if
  currentfile 1 (%%EOF) /SubFileDecode filter
  flushfile
  cleardictstack
} bind def

% ===================== Restoring the PDF Document Structure ===============

/ResolveDict  % <dict> /ResolveDict -
{ dup {                                                 % d key val
    pop 1 index exch                                    % d cp key
    //DoNothing //ResolveD exec                         % d obj
    pop                                                 % d
  } forall
  pop                                                   %
} bind def

/SetupPageView  % <obj> SetupPageView -
{
  //PDFR_DEBUG {
    (SetupPageView beg) =
  } if
//DSC_OPDFREAD not {
  //GraphicState /InitialMatrix get setmatrix
} if
  /MediaBox get aload pop                               % bx0 by0 bx1 by1
  3 index neg 3 index neg translate % Temporary move to origin
  3 -1 roll sub 3 1 roll exch sub exch                  % bw bh
  userdict  /.HWMargins //knownget exec {
    aload pop
  } {
    currentpagedevice /.HWMargins //knownget exec {
      aload pop
    } {
      0 0 0 0
    } ifelse
  } ifelse
  currentpagedevice /PageSize get aload pop
  3 -1 roll sub 3 1 roll exch sub exch                  % bw bh px0 py0 px1 py1
  exch 3 index sub exch 3 index sub                     % bw bh px0 py0 pw ph
  //SetPageSize {
    //PDFR_DEBUG {
      (Setting page size to ) print 1 index //=only exec ( ) print dup =
    } if
    pop pop 3 index 3 index 2 copy                      % bw bh px0 py0 bw bh bw bh
    currentglobal false setglobal 3 1 roll              % bw bh px0 py0 bw bh bool bw bh
    currentpagedevice dup /PageSize known {
      /PageSize get aload pop                           % Get current page size
    } {
      0 0                                               % dummy page size values if not known
    }ifelse
                                                        % bw bh px0 py0 bw bh bool bw bh Width Height
    round cvi 2 index round cvi eq                      % bw bh px0 py0 bw bh bool bw bh Width bool
    exch round cvi 3 index round cvi eq and             % bw bh px0 py0 bw bh bool bw bh bool
    {                                                   % Page Size unchanged, do not emit setpagedevice
      pop pop                                           % bw bh px0 py0 bw bh bool
    } {
      /MediaRequested where {
                                                        % bw bh px0 py0 bw bh
        /MediaRequested get aload pop                   % bw bh px0 py0 bw bh Width Height
        round cvi 2 index round cvi eq                  % bw bh px0 py0 bw bh bool bw bh Width bool
        exch round cvi 3 index round cvi eq and         % bw bh px0 py0 bw bh bool bw bh bool
        {pop pop false}                                         % We already requested this media size, so don't re-request
        {true} ifelse                                   % Media request different to last request
      } {
        true                                            % No stored media request, so apply setpagedevice
      } ifelse
      {
        2 array astore                                    % bw bh px0 py0 bw bh bool []
        dup /MediaRequested exch def
        << exch /PageSize exch >> setpagedevice           % bw bh px0 py0 bw bh bool
        /pagesave save def
      } if
    } ifelse
    userdict /PDFR_InitialGS gstate put
    setglobal                                           % bw bh px0 py0 bw bh
  } if
  //RotatePages {
    2 copy gt 6 index 6 index gt ne {
      % a rotation is useful except it fits with no rotation.
      1 index 5 index le 1 index 5 index le and not
    } {
      false
    } ifelse
  } {
    false
  } ifelse
  { //CenterPages {
        //PDFR_DEBUG {
          (Rotating page, and then centering it) ==
        } if
        90 rotate
        0 5 index neg translate
        5 index 1 index exch sub 2 div
        2 index 6 index sub 2 div neg                   % bw bh px0 py0 pw ph lm bm
        translate
    } {
      //FitPages {
        1 index 5 index div 1 index 7 index div         % bw bh px0 py0 pw ph sx sy
        2 copy gt {
          exch
        } if
        pop dup scale                                   % bw bh px0 py0 pw ph
      } if
      90 rotate
      0 5 index neg translate
    } ifelse
  } {
    //CenterPages {
        //PDFR_DEBUG {
          (Ccentering page) ==
        } if
        1 index 6 index sub 2 div
        1 index 6 index sub 2 div                       % bw bh px0 py0 pw ph lm bm
        translate
    } {
      //FitPages {
        1 index 6 index div 1 index 6 index div         % bw bh px0 py0 pw ph sx sy
        2 copy gt {
          exch
        } if
        pop dup scale                                   % bw bh px0 py0 pw ph
      } if
    } ifelse
  } ifelse
  pop pop                                               % bw bh px0 py0
  translate                                             % bw bh
  pop pop                                               %
  //PDFR_DEBUG {
    (SetupPageView end) =
  } if
} bind def

/PageContentsDaemon % <id> <obj> <node> PageContentsDaemon <id> <obj>
{ % Note: an excessive operand from a prebond procedure.
  //PDFR_DEBUG {
    (Executing PageContentsDaemon for ) print 2 index =
  } if                                                  % id obj node
  1 index exch /Context exch put                        % id obj
  dup /ImmediateExec true put
  dup /IsPage true put
  SetPageSize {dup /Context get //SetupPageView exec} if
} bind def

/FontFileDaemon % <id> <obj> <font_descriptor> FontFileDaemon <id> <obj>
{ % Note: an excessive operand from a prebond procedure.
  //PDFR_DEBUG {
    (Executing FontFileDaemon for ) print 2 index =
  } if
  % We need any font resource that refers this descriptor
  % to know the font type. Assuming that FontDescriptorDaemon
  % provided FontFileType.
  dup /FontFileType get                                 % id obj fd ft
  2 index exch                                          % id obj fd obj ft
  dup //ReadFontProcs exch //knownget exec {            % id obj fd obj ft proc
     exch pop exec                                      % id obj fd
  } {
    mark (FontFile reader for ) 2 index ( isn't implemented yet.) //error exec
  } ifelse
  //PDFR_DEBUG {
    (FontFileDaemon end) =
  } if                                                  % id obj fd
  pop
} bind def

/FontDescriptorDaemon % <id> <obj> <font_resource> FontDescriptorDaemon <id> <obj>
{ % Note: an excessive operand from a prebond procedure.
  //PDFR_DEBUG {
    (Executing FontDescriptorDaemon for ) print 2 index =
  } if                                                  % id obj fr
  %HACK BEG assuming an own font for each font descriptor
          % to provide an access to PDFEncoding
          % from MakeType42, ComposeCharStrings.
    2 copy /FontResource exch put
  %HACK END
  /Subtype get 1 index exch /FontFileType exch put
} bind def

/UnPDFEscape {	% <namepdf> UnPDFEscape <nameps>
  dup dup length string cvs				    % /namepdf (name)
  dup (#) search {
    % name contains PDF-style escapes ("#hh") that need to be removed
    {												% ... (po..st) (#) (pre)
      pop											% ... (po..st) (#)
      (16#--) 2 index 0 2 getinterval				% ... (po..st) (#) (16#--) (po)
      1 index 3 2 getinterval copy pop				% ... (po..st) (#) (16#po)
      cvi											% ... (po..st) (#) 16#po
      0 exch put									% ... (po..st); 16#po patched into (#)
      0												% ... (po..st) 0
      1 index 2 1 index length 2 sub getinterval    % ... (po..st) 0 (..st)
      3 copy putinterval							% ... (..stst) 0 (XXst)
      length										% ... (..stst) 0 LEN_OF_(po..st)-2
      3 copy exch put								% ... (..st\0t) 0 LEN_OF_(po..st)-2
      getinterval									% ... (..st), stored at begining of old (po..st)
      (#) search not {
        pop exit				    % /namepdf (nameps\0..)
      } if
    } loop
    % we have a '\0' marker (not allowed in PDF names) after all usefull characters
    (\0) search pop exch pop exch pop
    cvn
    exch pop
  } {
    pop pop
  } ifelse
} bind def

/TypeDaemons <<  % <id> <obj> proc <id> <obj>
  /Page
  { //PDFR_DEBUG {
      (Recognized a page.) =
    } if
    dup /Contents //knownget exec {                     % id obj c
      0 get //DoNothing exch                            % id obj dn id1
      [ % <id> <obj> proc <id> <obj>
        3 index //PageContentsDaemon /exec load
      ] cvx                                             % id obj {}
      //Register exec                                   % id obj
    } {
      (fixme: page with no Contents won't be printed.) =
    } ifelse
  } bind
  /FontDescriptor
  { //PDFR_DEBUG {
      (Recognized a font descriptor.) =
    } if
    dup /FontName //knownget exec {
        1 index /FontName 3 -1 roll //UnPDFEscape exec put
    } if
    dup dup /FontFile known {/FontFile} {/FontFile2} ifelse
    //knownget exec {                                 % id obj ff
      0 get //DoNothing exch                          % id obj dn id1
      [ % <id> <obj> proc <id> <obj>
        3 index //FontFileDaemon /exec load
      ] cvx                                           % id obj {}
      //Register exec                                 % id obj
    } {
      % FontFile3 are not implemented yet.
      (Font descriptor ) print 1 index =only ( has no FontFile.) =
    } ifelse
  } bind
  /Font
  { //PDFR_DEBUG {
      (Recognized a font resource.) =
    } if
    dup /BaseFont //knownget exec {
      //UnPDFEscape exec 2 copy /BaseFont exch put
      % cache the installed font (if any) before replacing it.
      //PDFReader /RemoveFontNamePrefix get exec
      currentglobal exch % A hack against HP LaserJet 1320 bug :
                         % It sets the local allocation mode
                         % when 'resourcestatus' fails.
      dup /Font resourcestatus {
        pop pop
        //PDFReader /GetInstalledFont get exec pop
      } {
        pop
      } ifelse
      setglobal
    } if
    dup /FontDescriptor //knownget exec {               % id obj fd
      0 get                                             % id obj id1
      dup //IsRegistered exec {                         % id obj id1
        //PDFR_DEBUG {
          (already registered ) print dup =
        } if
        pop
      } {
        //DoNothing exch                                % id obj dn id1
        [ % <id> <obj> proc <id> <obj>
          3 index //FontDescriptorDaemon /exec load
        ] cvx                                           % id obj {}
       //Register exec                                  % id obj
      } ifelse
    } if
  } bind
>> def

/MakeStreamReader % <obj> MakeStreamReader <file>
{ dup
  [
    exch
    //PDFR_DEBUG {
      (Stream proc )
      /print load
      //PDFR_STREAM {
        (<)
        /print load
      } if
    } if
    1 dict dup /i -1 put
    /dup load
    /i
    /get load
    1
    /add load
    /dup load
    3
    1
    /roll load
    /i
    /exch load
    /put load
    //knownget
    /exec load
    /not load
    { () }
    /if load
    //PDFR_DEBUG {
      //PDFR_STREAM {
        /dup load
        /print load
        (>)
        /print load
      } if
      ( end of stream proc.\n)
      /print load
    } if
  ] cvx
  //PDFR_DEBUG {
    (Stream reader ) print dup ==
  } if
  0 () /SubFileDecode filter
  exch //AppendFilters exec
} bind def

/RunDelayedStream % <stream_obj> RunDelayedStream -
{
  % Save InitialTextMatrix, as this is local to each content stream
  //GraphicState /InitialTextMatrix get
  //InitialTextMatrixStack //PDFReader /InitialTextMatrixStackPointer get
    2 copy get null eq {
      2 copy currentglobal true setglobal matrix exch setglobal put
    } if
  get copy pop
  //PDFReader /InitialTextMatrixStackPointer 2 copy get 1 add put
  % Execute the stream
  //MakeStreamReader exec                                       % file
  mark exch
  cvx exec                                                      %
  counttomark 0 ne {
    mark (Data left on ostack after a delayed stream execution.) //error exec
  } if
  cleartomark
  % Restore InitialTextMatrix
  //PDFReader /InitialTextMatrixStackPointer 2 copy get 1 sub put
  //InitialTextMatrixStack //PDFReader /InitialTextMatrixStackPointer get get
  //GraphicState /InitialTextMatrix get
  copy pop
} bind def

% ===================== Font Management ======================

//ReadFontProcs begin
  /Type1   % <font_descriptor> <FontFile_object> Type1 <font_descriptor>
  { //PDFR_DEBUG {
      (ReadFontProcs.Type1) =
    } if
    dup /.endobj_daemon [ 4 index //HookFont /exec load ] cvx put
    dup /ImmediateExec true put
    /GlobalExec true put
  } bind def
  /MMType1 //Type1 def
  /TrueType   % <font_descriptor> <FontFile_object> TrueType <font_descriptor>
  { //PDFR_DEBUG {
      (ReadFontProcs.TrueType) =
    } if
    dup /.endobj_daemon [ 4 index //HookFont /exec load ] cvx put
    pop
  } bind def
end

% A working dictionary to hold items related to reading a TrueType font
% and converting into a type 42 font, especially regarding creating the sfnts
% array of strings, and ensuring strings are split on table boundaries and
% for the glyf table, on glyph boundaries.
%
/.opdloadttfontdict 50 dict def
.opdloadttfontdict begin

/maxstring 65400 def    % less than the maximum length of a PostScript string,
                        % must be a multiple of 4 (for hmtx / loca / vmtx)
end

% Uses an insertion sort to sort the contents of an array,
% the sorted array is returned. Takes the array to sort and a
% comparison procedure. The comparison procedure must take two
% arguments, and return a boolean. The return value should be
% false if arguments incorrectly ordered, true if they are
% already in the correct order.
%
% [Array to sort] {comparisaon proc} InsertionSort [Sorted array]
%
/.InsertionSort
{
    /CompareProc exch def
    /Array exch def
    1 1 Array length 1 sub
    {
        /Ix exch def
        /Value1 Array Ix get def

        /Jx Ix 1 sub def
        {
            Jx 0 lt {
                exit
            } if
            /Value2 Array Jx get def
            Value1 Value2 CompareProc {
                exit
            } if

            Array Jx 1 add Value2 put
            /Jx Jx 1 sub def
        } loop
        Array Jx 1 add Value1 put
    } for
    Array
} bind def

%
% Utility rourtines to insert a TrueType data type
%
% <string> <index> <integer> putu16 -
/putu16 {
  3 copy -8 bitshift put
  exch 1 add exch 16#ff and put
} bind def
% <string> <index> <integer> putu32 -
/putu32 {
  3 copy -16 bitshift putu16
  exch 2 add exch 16#ffff and putu16
} bind def

%
% Utility routines to read TrueType table data, returning
% either a string or an array of strings depending on the
% table length.
%

% Read a table as a single string.
% <file> <length> .readtable <string>
/.readtable {
  dup dup 1 and add string
        % Stack: f len str
  dup 0 4 -1 roll getinterval
        % Stack: f str str1
    % Because of the absurd PostScript specification that gives an
    % error for reading into an empty string, we have to check for
    % this explicitly here.
  3 -1 roll exch
  dup () ne { readstring } if pop pop
} bind def

% Read a big table (one that may exceed 64K).
% <file> <length> .readbigtable <string[s]>
/.readbigtable {
  dup maxstring lt {
    .readtable
  } {
    currentuserparams /VMReclaim get -2 vmreclaim
    [ 4 2 roll {
        % Stack: mark ... f left
      dup maxstring le { exit } if
      1 index maxstring string readstring pop 3 1 roll maxstring sub
    } loop .readtable ]
    exch vmreclaim
  } ifelse
} bind def

% ReadTTF reads the tables and so on from a TreuType font into memory
% so that they are available for later processing.
%
% <filename> ReadTTF -
%
/ReadTTF
{
  .opdloadttfontdict begin
  /TTFontFile exch def

  % Table directory:
  %  version       -    fixed (4 bytes)
  %  numTables     -    USHORT (2 bytes)
  %  searchRange   -    USHORT (2 bytes)
  %  entrySelector -    USHORT (2 bytes)
  % Read Table
  /TableDir TTFontFile 12 string readstring pop def

  % There are numTables table directory entries:
  %   tag          -    ULONG (4 bytes)
  %   checkSum     -    ULONG (4 bytes)
  %   offset       -    ULONG (4 bytes)
  %   length       -   ULONG (4 bytes)
  % Read entries
  /tables TTFontFile TableDir 4 getu16 16 mul string readstring pop def

  % Create dictionary to store directory entries.
  /tabarray tables length 16 idiv array def

  % Check version for TrueType collection
  TableDir 0 4 getinterval (ttcf) eq {
      QUIET not { (Can't handle TrueType font Collections.) = } if
      /.loadttfonttables cvx /invalidfont signalerror
  } {
    % There are ((length of tables string) / 16) Table directory entries
    % Get and store each in turn
    0 16 tables length 1 sub {
      % Get each directory entry as a 16-byte string
      dup                                       % index index
      tables exch 16 getinterval                % index (string)
        exch 16 div cvi exch                    % index/16 (string)
      tabarray  3 1 roll put
    } for
  } ifelse

  % We need the tables in the order they occur in the file, so sort
  % by 'offset'.
  tabarray { exch 8 getu32 exch 8 getu32 gt} .InsertionSort pop

  % Now we read the content of each table in turn. If the table is < 64K
  % then we store it in a single string. If its more, we store it in an
  % array of strings. The table contents are stored in 'tabs' in the same
  % order as they are read from the file, as per the sorted array 'tabarray'.
  /Read TableDir length tables length add def
  /tabs [
    tabarray {
      % Get offset (from start of file) of next table
      dup 8 getu32                                        % () offset
      % Subtract amount read so far
      Read sub                                            % () offset-Read
      dup 0 gt {
      % Read and discard any extra padding bytes          % () offset-Read
      dup string TTFontFile exch readstring pop pop       % () offset-Read
      % Update bytes read
      Read add /Read exch def                             % ()
      } {
       pop                                                % ()
      } ifelse
      % Find length of this table and add it to bytes read
      12 getu32                                           % () tablelength
      dup Read add                                        % () tablelength tablelength+Read
      /Read exch def                                      % () tablelength
      TTFontFile exch .readbigtable
    } forall
  ] def
  end % .opdloadttfontdict
} bind def

% GetLocaType finds the head table in tabarray, which gives
% an index into the 'tabs' array where the data is stored.
% From that data we extract the loca type (short or long).
%
% - GetLocaType -
%
/GetLocaType
{
  0 1 tabarray length 1 sub{
                                  % control-variable
    dup tabarray exch get         % control-variable ()
    0 4 getinterval (head) eq{    % control-variable bool
      tabs exch get               % ()
      50 gets16
      /LocaType exch def
      exit
    } {
      pop % control variable      % -
    } ifelse
  } for
} bind def

% GetNumGlyphs finds the maxp table in tabarray, which gives
% an index into the 'tabs' array where the data is stored.
% From that data we extract the number of glyphs in the font.
%
% - GetNumGlyphs -
%
/GetNumGlyphs
{
  0 1 tabarray length 1 sub{
                                  % control-variable
    dup tabarray exch get         % control-variable ()
    0 4 getinterval (maxp) eq{    % control-variable bool
      % Get the maxp string
      % from the tabs array
      tabs exch get               % ()
      4 getu16                    % int
      /NumGlyphs exch def
      exit                        % int
    } {
      pop % control variable      % -
    } ifelse
  } for
} bind def

% StringtoLoca takes a string, and an index in to an array
% where the loca results should be stored from. It reads
% along the string getting either 2-byte or 4-byte values
% (depends on loca type) and stores them in the array at
% successive locations. Leaves the next unused location
% on the stack at end (easy to process multiple strings).
%
% string ArrayIndex StringToLoca  ArrayIndex
%
/StringToLoca
{
  /LocaIndex exch def                        % ()
  /StringOffset 0 def                        % ()
  {
    dup length StringOffset gt {             % ()
      dup                                    % ()
      LocaType 1 eq{
        StringOffset getu32                  % () loca
        LocaArray LocaIndex 3 -1 roll put    % ()
        /LocaIndex LocaIndex 1 add def       % ()
        /StringOffset StringOffset 4 add     % ()
        def
      } {
        StringOffset getu16 2 mul            % () loca
        LocaArray length LocaIndex gt {      % take account of apdding in the string
          LocaArray LocaIndex 3 -1 roll put  % ()
        }{                                   %
          pop                                % ignore indices off the end of the array
        }ifelse                              %
        /LocaIndex LocaIndex 1 add def       % ()
        /StringOffset StringOffset 2 add     % ()
        def
      } ifelse
    }{                                       % ()
      pop                                    % -
      LocaIndex                              % return index
      exit
    }ifelse
  } loop
} bind def

% GetSortedLoca reads the loca table, and sorts it by offset
% this is so that we can walk up the array looking for an approporiate
% place to split strings. The result is stored in LocArray
%
% - GetSortedLoca -
%
/GetSortedLoca
{
  NumGlyphs 1 add array /LocaArray exch def

  % Get the loca table
  0 1 tabarray length 1 sub{
                                 % control-variable
    dup tabarray exch get        % control-variable ()
    0 4 getinterval (loca) eq{   % control-variable bool
      % Get the loca string
      % from the tabs array
      tabs exch get              % ()
      exit
    } {
      pop % control variable     % -
    } ifelse
  } for

  % If its a single string handle the easy way
  dup type /stringtype eq {
    0 StringToLoca pop
  }{
    % Otherwise its an array, process each string in the array
    0 exch % Starting LocaArray index
    {
      exch StringToLoca
    }forall
    pop % final LocaArray index
  }ifelse

  % Now we've read all the locations, sort them so
  % we can figure out where to break the strings
  LocaArray {gt} .InsertionSort pop
} bind def

% Updates internal storage with a new string from the
% GlyfArray
% - GetWorkingString -
/GetWorkingString
{
  WorkString 0
  GlyfArray GlyfStringIndex get
  putinterval
  % Update the available bytes
  /WorkBytes GlyfArray GlyfStringIndex get length def
  % Set index to get data from next string in array
  /GlyfStringIndex GlyfStringIndex 1 add def
} bind def

% Returns a string with the requested number of bytes taken
% from WorkingString. There must be enough data in WorkingString to
% satisfy the request
%
/GetWorkingBytes
{
  /BytesToRead exch def
  % Get 'BytesToRead' bytes from working store
  WorkString 0 BytesToRead getinterval
  dup length string copy
  % Get remaining bytes from working store
  WorkString BytesToRead WorkBytes BytesToRead sub getinterval
  dup length string copy
  % replace first 'n' bytes of working store with unread bytes
  WorkString 0 3 -1 roll putinterval
  % Subtract bytes read from bytes available
  /WorkBytes WorkBytes BytesToRead sub def
} bind def

% Read 'int' bytes from GlyfArray strings, return string composed
% of those bytes
%
% int GetGlyfBytes string
/GetGlyfBytes
{
  /ToRead exch def

  % If we have no available data, get soem from the array of
  % glyf strings
  WorkBytes 0 eq {
    GetWorkingString
  } if

  WorkBytes ToRead ge {
    ToRead string dup 0
    ToRead GetWorkingBytes putinterval
  }{
    % Create a string sized to hold the target data
    ToRead string
    % Get remaining stored bytes, and put at the start
    % of the string
    dup
    % Start of string
    0
    % Get remaining bytes
    WorkString 0 WorkBytes getinterval
    % store at start of output string
    putinterval

    dup
    % Location in output to store data from next string
    WorkBytes
    % amout of data required to read from next string
    ToRead WorkBytes sub
    % Get the next string from the array of strings
    GetWorkingString
    % Get a string containing the required data, updating
    % the internal data storage
    GetWorkingBytes
    % put the data at the end of the stored data in the
    % output string
    putinterval
  } ifelse
} bind def

% Given an array of glyf strings, returns an array of strings
% split on glyf boundaries
%
% [] SplitGlyf []
%
/SplitGlyf
{
  /GlyfArray exch def
  /DestArray GlyfArray length 2 mul array def
  /DestArrayIndex 0 def

  /LastLoca 0 def
  /NextLocaIndex 0 def
  /LastLocaIndex 0 def

  /GlyfStringIndex 0 def
  /WorkString maxstring string def
  /WorkBytes 0 def

  % Find appropriate next loca
  {
    % Get location of next glyph
    LocaArray NextLocaIndex get                      % int
    % subtract location of last point to get
    % the actual bytes between
    LastLoca sub maxstring gt                        % int bool
    {
      LocaArray LastLocaIndex get LastLoca sub
      GetGlyfBytes                                   % ()
      DestArray DestArrayIndex 3 -1 roll put         % -
      /DestArrayIndex DestArrayIndex 1 add def       % -
      LocaArray LastLocaIndex get /LastLoca exch def % -
    } {                                              % int
      /LastLocaIndex NextLocaIndex def               % -
      /NextLocaIndex NextLocaIndex 1 add def         % -
      NextLocaIndex NumGlyphs gt                     % bool
      {
        WorkBytes                                    % int
        GlyfStringIndex GlyfArray length lt {        % int bool
          GlyfArray GlyfStringIndex get length       % int
          add string dup                             % (d) (d)
          0                                          % (d) (d) 0
          WorkString 0 WorkBytes getinterval         % (d) (d) (s)
          putinterval                                % (d)
          dup                                        % (d) (d)
          WorkBytes                                  % (d) (d) int
          GetWorkingString                           % (d) (d) int
          WorkString 0 WorkBytes getinterval         % (d) (d) int (s)
          putinterval                                % (d)
        } {
          pop                                        % -
          WorkString 0 WorkBytes getinterval         % ()
        } ifelse
        dup length string copy
        DestArray DestArrayIndex 3 -1 roll put
        exit
      } if
    } ifelse
  } loop
  DestArray

} bind def

% ProcessTTData looks at the data stored in the 'tabs' array and does several things:
% 1) Make sure strings representing tables are multiples of 4 bytes long
% 2) For arrays representing tables, make sure the total string length is a multiple
%    of 4 bytes long, to ensure the table is a multiple of 4 bytes.
% 3) Handle the glyf table specislly, each string in this array must be split on the
%    boundary of a glyf. Use the loca table to determine where the split should happen
%    and build a new array of strings split appropriately.
%
% - ProcessTTData -
%
/ProcessTTData
{
  .opdloadttfontdict begin
    % Make sure all the strings are a multiple of 4 bytes
    0 1 tabarray length 1 sub{
        /ix exch def
        tabarray ix get
        12 getu32 dup maxstring le {
          % String < 64Kb, still need to check if its a multiple of 4
          dup 4 mod 0 ne {
            4 div cvi 1 add 4 mul string /newstring exch def
            /oldstring tabs ix get def
            newstring 0 oldstring putinterval
            0 1 newstring length oldstring length sub 1 sub {
              newstring exch oldstring length add 0 put
            } for
            tabs ix newstring put
          } {
            % table size is a multiple of 4, don't need to promote it
            pop
          } ifelse
        }{
          % table size > 64K, so this is an array of strings, not a string
          % We still need to make sure that the tables end on 4-byte
          % boundaries.
          dup 4 mod 0 ne {
            % First we need to work out how many strings of size maxstring
            % are present, and how much they contribute to the overall size.
            dup maxstring idiv maxstring mul sub
            % Promote final string length to multiple of 4
            4 idiv 1 add 4 mul string /newstring exch def
            % Get array of strings
            tabs ix get
            % find size of table and get last string
            dup length 1 sub dup /iy exch def get /oldstring exch def
            newstring 0 oldstring putinterval
            0 1 newstring length oldstring length sub 1 sub {
              newstring exch oldstring length add 0 put
            } for
            tabs ix get iy newstring put
          } {
            % table size is a multiple of 4, don't need to promote it
            pop
          } ifelse
        } ifelse
    } for

    % Now, if glyf table > 64Kb, then it will be an array of strings
    % We need to make sure the strings are split on glyph boundaries
    0 1 tabarray length 1 sub {            % int
      dup tabarray exch get                % int ()
      dup 12 getu32 maxstring gt {         % int () bool
        0 4 getinterval dup (glyf) eq{     % int () bool
          % Need to split the glyf strings on glyph boundaries, hmmm.
          pop                              % int
          % We need to know the number of glyphs (from the maxp table) and the
          % position of each glyph (from the loca table).
          GetLocaType                      % int
          GetNumGlyphs                     % int
          GetSortedLoca                    % int
          % Get the array of strings from tabs
          dup tabs exch get                % int
          SplitGlyf                        % int []
          tabs 3 1 roll put                % -
        } {                                % int ()
          (Warning, table ) print print ( > 64Kb\n) print
          pop                              % -
        } ifelse
      }{                                   % int ()
        % Table less than 64K, so don't worry
        pop % directory entry              % int
        pop % 'for' control variable       % -
      } ifelse
    } for
  end % .opdloadttfontdict
} bind def

% Makesfnts uses the accumulated data to create an array of strings
% containing only the required data.
%
% - Makesfnts array
%
/Makesfnts
{
  .opdloadttfontdict begin
    % Determine size of sfnts array
    % length of tabarray + header
    0
    tabs {                            % int obj
      dup type /stringtype eq {       % int obj bool
        pop                           % int
        1 add                         % int
      }{                              % int obj
        {                             % int obj
          type /stringtype eq {       % int bool
            1 add                     % int
          } if
        } forall
      } ifelse
    } forall

    1 add                            % add header and table directory
                                     % to determine total # strings
    % Need to recalculate the lengths of the TT
    % tables, just in case any have changed. If required we
    % could also resort the tables here, ideally we should do so
    % and recalculate checksums, but this should never be necessary
    % for fonts produced by pdfwrite.
    /TTOffset
    TableDir length                  % initial table offset is header length
    tabarray length 16 mul add       % + (NumTables * 16) bytes
    def

    0
    tabarray {                     % index ()
      exch dup 1 add               % () index index+1
      3 1 roll                     % index+1 () index
      dup                          % index+1 () index index
      tabs exch get                % index+1 () index ()/[]
      dup type /stringtype eq {    % index+1 () index ()/[] bool
        length                     % index+1 () index int
        2 index exch               % index+1 () index () int
        TTOffset
        dup 3 1 roll add           % add the running total of offsets
        /TTOffset exch def         % update running total of offsets
        8 exch putu32              % index+1 () index
        exch tabarray 3 1 roll     % index+1 [] index ()
        put                        % index+1
      } {                          % index+1 () index ()/[]
        0 exch                     % add all string lengths
        {                          % starting from 0
          dup type /stringtype eq {
            length add             %
          } {
            pop
          } ifelse
        } forall                   %
        2 index exch               % index+1 () index () int
        TTOffset
        dup 3 1 roll add           % add the running total of offsets
        /TTOffset exch def         % update running total of offsets
        8 exch putu32              % index+1 () index
        exch tabarray 3 1 roll     % index+1 [] index ()
        put                        % index+1
      } ifelse
    } forall
    pop                            % index+1

    array                          % []
    dup 0                          % [] [] 0
    TableDir length
    tables length add              % [] [] 0 header_length
    string                         % [] [] 0 ()
    dup 0 TableDir putinterval     % [] [] 0 ()
    dup 12 tables putinterval      % [] [] 0 ()
    put                            % []
    dup                            % [] []
    /ix 1 def
    tabs {                         % [] [] obj
      dup type /stringtype eq {    % [] [] obj bool
        ix exch                    % [] [] int obj
        put dup                    % [] []
        /ix ix 1 add def           % [] []
      }{
        {
          dup type /stringtype eq { % [] [] obj bool
            ix exch put dup        % [] []
            /ix ix 1 add def       %
          } {
            pop                    % [] []
          } ifelse
        } forall
      } ifelse
    } forall
    pop                            % []
    end %.opdloadttfontdict
} bind def

/MakeType42 % <FontFile_object> <font_descriptor> MakeType42 <FontFile_object> <font_descriptor> <font>
{
  //PDFR_DEBUG {
    (MakeType42 beg) =
  } if
  10 dict begin
    /FontName 1 index /FontName get def
    /FontType 42 def
    /FontMatrix [1 0 0 1 0 0] def
    /FontBBox 1 index /FontBBox get def          % fo fd
    dup /FontResource get                        % fo fd fr
    dup /Encoding known {                        % fo fd fr
       //PDFReader /ObtainEncoding get exec      % fo fd fr
       /Encoding get                             % fo fd e
    } {
      pop null
    } ifelse
    /PDFEncoding exch def                        % fo fd
    /CharStrings 2 index //PDFReader /MakeTTCharStrings get exec def
    /sfnts 2 index //MakeStreamReader exec
    ReadTTF
    ProcessTTData
    Makesfnts
    def
    /Encoding StandardEncoding def % A stub - will be replaced by font resource.
    /PaintType 0 def
  currentdict end
  //PDFR_DEBUG {
    (MakeType42 end) =
  } if
} bind def

/GetInstalledFont % <name> GetInstalledFont <font>
{
  dup //InstalledFonts exch knownget {                          % n f
    exch pop                                                    % f
  } {                                                           % n
    dup findfont dup 3 1 roll                                   % f n f
    //InstalledFonts 3 1 roll put                               % f
  } ifelse
} bind def

/RemoveFontNamePrefix % <name> RemoveFontNamePrefix <name>
{ //=string cvs true
  0 1 5 {
    2 index exch get //IsUpper exec not {
      pop false exit
    } if
  } for
  { (+) search {
      pop pop
    } if
  } if
  cvn
} bind def

/CheckFont % <key> <val> CheckFont <key> <val>
{ dup /Type get /Font ne {
    mark (Resource ) 3 index ( must have /Type/Font .) //error exec
  } if
} bind def

/CheckEncoding %  <key> <val> CheckEncoding <key> <val>
{ dup type /nametype ne {
    dup /Type get /Encoding ne {
      mark (Resource ) 3 index ( must have /Type/Encoding .) //error exec
    } if
  } if
} bind def

/ObtainEncoding % <font_resource> ObtainEncoding <font_resource>
{ dup /Encoding known {
    dup dup /Encoding //CheckEncoding //ResolveD exec   % fr fr er|e|n
    dup type dup /arraytype eq exch /packedarraytype eq or {
      % Already resolved.
      pop pop
    } {
      dup type /nametype eq {
        /Encoding findresource                          % fr fr e
      } {
        dup /BaseEncoding //knownget exec not {
          /StandardEncoding
        } if
        /Encoding findresource                          % fr fr er e
        exch                                            % fr fr e er
        /Differences //knownget exec {                  % fr fr e d
          exch dup length array copy exch
          0 exch                                        % fr fr e 0 d
          {                                             % fr fr e i v
            dup type /integertype eq {
              exch pop
            } {
              3 copy put pop                            % fr fr e i
              1 add
            } ifelse
          } forall
          pop                                           % fr fr e
         } if                                           % fr fr e
      } ifelse                                          % fr fr e
      /Encoding exch put                                % fr
    } ifelse
  } {
    dup /Encoding /StandardEncoding /Encoding findresource put
  } ifelse
} bind def

/ObtainMetrics % <font_resource> ObtainMetrics <font_resource>
{ dup /Widths //knownget exec {                         % fr W
    1 index /Encoding get                               % fr W E
    256 dict                                            % fr W E M
    3 index /Subtype get /TrueType eq {
      1000
    } {
      1
    } ifelse                                            % fr W E M s
    4 index /MissingWidth //knownget exec not {
      0
    } if                                                % fr W E M s mw
    5 index /FirstChar //knownget exec not {
      0
    } if                                                % fr W E M s mw c0
    6 5 roll                                            % fr E M s mw c0 W
    dup 0 exch 1 exch length 1 sub {                    % fr E M s mw c0 W i
      2 copy get                                        % fr E M s mw c0 W i w
      exch 3 index add                                  % fr E M s mw c0 W w c
      7 index exch get                                  % fr E M s mw c0 W w n
      dup dup null ne exch /.notdef ne and {
        6 index 3 1 roll exch                           % fr E M s mw c0 W M n w
        6 index div
        3 copy pop //knownget exec {
          0 eq
        } {
          true
        } ifelse
        { put                                           % fr E M s mw c0 W
        } {
          pop pop pop
        } ifelse
      } {
        pop pop
      } ifelse
    } for
    pop pop pop pop exch pop                            % fr M
    1 index exch /Metrics exch put                      % fr
  } {
    dup /MissingWidth //knownget exec {                 % fr mw
      256 dict                                          % fr mw M
      2 index /Encoding get {                           % fr mw M e
        dup null ne {
          3 copy 3 2 roll put                           % fr mw M e
        } if
        pop                                             % fr mw M
      } forall
      exch pop                                          % fr M
      1 index exch /Metrics exch put                    % fr
    } if
  } ifelse
} bind def

/NotDef % - NotDef -
{ % A Type 3 font is on dstack.
  FontMatrix aload pop pop pop exch pop exch pop        % sx sy
  1 exch div exch
  1 exch div exch                                       % wx wy
  1 index 0 setcharwidth
  0 setlinewidth
  0 0 moveto
  2 copy rlineto
  1 index 0 rlineto
  neg exch neg exch rlineto                             %
  closepath stroke
} bind def

%% These two routines may have more general application.
%% When executing BuildChar we need to run in the context of the font
%% as far as resources are concerned (in case the glyph uses another font)
%% but since we are executing a page stream, we must not lose the original
%% context, or we won't be able to find page resources. Originally this was
%% a simpler routine, but this failed when presented with a type 3 font
%% whose BuildChar/CharProcs used another type 3 font
/SaveResourcesToStack
{
  [
  //PDFReader /OldResources known {
    //PDFReader /OldResources get
  }{
    null
  } ifelse
  //PDFReader /CurrentObject get /Context get /Resources get
  ]
  //PDFReader /OldResources 3 -1 roll put
}bind def

/RestoreResourcesFromStack
{
  //PDFReader /OldResources get dup
  0 get //PDFReader /OldResources 3 -1 roll put
  1 get //PDFReader /CurrentObject get /Context get /Resources 3 -1 roll put
} bind def

/BuildChar  % <font> <char_code> BuildChar -
{ //PDFR_DEBUG {
    (BuildChar ) print dup //=only exec ( ) print
  } if
  exch begin
  Encoding exch get                                     % n
  //PDFR_DEBUG {
    dup =
  } if
  dup null eq {
    pop //NotDef exec                                   %
  }
  {                                                   % n
    CharProcs exch//knownget exec
    {
      currentfont /Font get /Resources //knownget exec{       %% Does the Font have any Resources ?
        exec                                                  %% Get them
        SaveResourcesToStack                                  %% Save the current Resources
        //PDFReader /CurrentObject get /Context get           %% Replace the current resources
        /Resources 3 -1 roll put                              %% With the Font resources
        //RunDelayedStream exec
        RestoreResourcesFromStack                             %% Restore the previous Resources
      } {
        //RunDelayedStream exec
      } ifelse
    }
    {
      //NotDef exec
    }ifelse
  } ifelse                                              %
  end % font
} bind def

/printdict % <dict> printdict -
{ (<<) =
  { exch = == } forall
  (>>) =
} bind def

/printfont % <dict> printfont -
{
  dup {
    exch dup =
    dup /Encoding eq {
      pop =
    } {
      dup /FontInfo eq exch /Private eq or {
        //printdict exec
      } {
        ==
      } ifelse
    } ifelse
  } forall
} bind def

/ScaleMetrics % <Metrics> <scale> ScaleMetrics <Metrics>
{ 1 index {           % M s n v
    2 index div       % M s n v'
    3 index           % M s n v' M
    3 1 roll put      % M s
  } forall
  pop
} bind def

/ResolveAndSetFontAux  % <resource_name> <size> ResolveAndSetFont -
{ exch dup                                              % s rn rn
  //PDFReader /CurrentObject get /Context get /Resources get
  /Font //DoNothing //ResolveD exec
  exch //CheckFont //ResolveD exec                      % s rn fr
  dup /Font //knownget exec {                           % s rn fr f
    exch pop exch pop
  } {
    {
      dup /Subtype get dup dup /Type1 eq exch /TrueType eq or exch /MMType1 eq or {
                                                        % s rn fr
        exch pop                                        % s fr
        dup /BaseFont get                               % s fr n
        //RemoveFontNamePrefix exec                     % s fr n
        //PDFR_DEBUG {
          (Font ) print dup =
        } if                                            % s fr n
        1 index /FontDescriptor known {                 % s fr n
          //PDFR_DEBUG {
            (Font from a font descriptor.) =
          } if
          1 index                                       % s fr n fr
          /FontDescriptor //DoNothing //ResolveD exec   % s fr n fd
          /Font //knownget exec {
            exch pop                                    % s fr fd
          } {
            //PDFR_DEBUG {
              (Font descriptor has no Font resolved.) =
            } if
            //GetInstalledFont exec                     % s fr f
          } ifelse
        } {
          //GetInstalledFont exec                       % s fr f
        } ifelse
        exch                                            % s f fr
        dup /Encoding known not {
          1 index /Encoding get 1 index exch /Encoding exch put
        } if
        //ObtainEncoding exec
        //ObtainMetrics exec
        exch
        dup length dict copy                            % s fr f
        dup 2 index /Encoding get                       % s fr f f e
        /Encoding exch put                              % s fr f
        1 index /Metrics //knownget exec {              % s fr f M
          2 index /Subtype get /TrueType ne {
            1 index /FontMatrix get 0 get
            dup 0 eq {
          % FontMatrix[0] == 0, so cannot downscale by it
              % HACK: downscale by FontMatrix[1], and will get the target value of wx as wy
              pop
              1 index /FontMatrix get 1 get
              dup 0 eq { pop 1 } if % sorry, FontMatrix is singular so cannot enforce the PDF metrics
            } if
            0.001 div
            //ScaleMetrics exec
          }{
            % Check if we got a /sfnts key in the dict
            % If we did then we are probably OK (TT font from GS)
            1 index /sfnts known not {
              % otherwise we need to check the FontMatrix
              1 index /FontMatrix get 0 get
              dup 0 eq {
                % FontMatrix[0] == 0, so cannot downscale by it
                    % HACK: downscale by FontMatrix[1], and will get the target value of wx as wy
                    pop
                    1 index /FontMatrix get 1 get
                    dup 0 eq { pop 1 } if % sorry, FontMatrix is singular so cannot enforce the PDF metrics
              } if
              //ScaleMetrics exec
            } if
          } ifelse
          1 index exch /Metrics exch put                % s fr f
        } if
        1 index /BaseFont get                           % s fr f n
        exch
        dup /FID undef
        dup /UniqueID undef
        definefont                                      % s fr f
        dup 3 1 roll                                    % s f fr f
        /Font exch put                                  % s f
        exit
      } if
      dup /Subtype get /Type3 eq {                      % s rn fr
        //ObtainEncoding exec
        2 copy exch /FontName exch put
        dup /CharProcs get //ResolveDict exec
        dup /FontType 3 put
        dup /BuildChar //BuildChar put
        dup dup /Font exch put
        % Ignore Metrics because pdfwrite duplicates it
        % from setcharwidth/setcachedevice.
        dup 3 1 roll                                    % s fr rn fr
        definefont                                      % s fr f
        2 copy ne {
          % The interpreter copied the font dictionary while 'definefont'
          % Need to update the font pointer in the resource.
          2 copy /Font exch put                         % s fr f
        } if
        exch pop                                        % s f
        exit
      } if
      dup /Subtype get /Type0 eq {                      % s rn fr
      } if
      dup /Subtype get /CIDFontType0 eq {               % s rn fr
      } if
      dup /Subtype get /CIDFontType2 eq {               % s rn fr
      } if
      mark (Unknown font type ) 2 index /Subtype get //error exec
    } loop
  } ifelse                                              % s f
  exch scalefont setfont                                %
} bind def

/ResolveAndSetFont  % <resource_name> <size> ResolveAndSetFont -
{
  //ResolveAndSetFontAux exec
} bind def

%%beg TrueType
% ================= Auxiliary procedures for True Type cmap Decoder =============

/.knownget
{ 2 copy known {
    get true
  } {
    pop pop false
  } ifelse
} bind def

/.min
{ 2 copy lt {
    exch
  } if
  pop
} bind def

/.max
{ 2 copy gt {
    exch
  } if
  pop
} bind def

/.dicttomark
{ >>
} bind def

% ===================== True Type cmap Decoder =============
% The following procedures are copied from gs/lib/gs_ttf.ps with no change.

% <string> <index> getu16 <integer>
/getu16 {
  2 copy get 8 bitshift 3 1 roll 1 add get add
} bind def

% <string> <index> gets16 <integer>
/gets16 {
  getu16 16#8000 xor 16#8000 sub
} bind def

% <string> <index> getu32 <integer>
/getu32 {
  2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add
} bind def

% <string> <index> gets32 <integer>
/gets32 {
  2 copy gets16 16 bitshift 3 1 roll 2 add getu16 add
} bind def

% Each procedure in this dictionary is called as follows:
%       <encodingtable> proc <glypharray>
/cmapformats mark
  0 {           % Apple standard 1-to-1 mapping.
    6 256 getinterval { } forall 256 packedarray
  } bind
  2 {           % Apple 16bit CJK (ShiftJIS etc)

    % /sHK_sz           subHeaderKey_size       % 1 * uint16
    % /sH_sz            subHeader_size          % 4 * uint16
    % /sH_len           subHeader_length
    % /cmapf2_tblen     total table length
    % /cmapf2_lang      language code (not used)
    % /sHKs             subHeaderKeys

    /sHK_sz 2 def
    /sH_sz 8 def
    dup 2 getu16 /cmapf2_tblen exch def

    dup 4 getu16 /cmapf2_lang exch def

    dup 6 256 sHK_sz mul getinterval /sHKs exch def

    0           % initialization value for /sH_len
    0 1 255 {
       sHKs exch
       2 mul getu16
       1 index  % get current max
       1 index  % get current subHeaderKey
       lt {exch} if pop
    } for
    /sH_len exch def

    dup 6 256 sHK_sz mul add
    cmapf2_tblen 1 index sub getinterval
    /sH_gIA exch def

    /cmapf2_glyph_array 65535 array def

    /.cmapf2_putGID {
        /cmapf2_ch cmapf2_ch_hi 8 bitshift cmapf2_ch_lo add def
        firstCode cmapf2_ch_lo le
        cmapf2_ch_lo firstCode entryCount add lt
        and { % true: j is inside
            sH_offset idRangeOffset add         % offset to gI
            cmapf2_ch_lo firstCode sub 2 mul    % rel. pos. in range
            add 6 add                           % offset in sH_gIA
            sH_gIA exch getu16
            dup 0 gt { %
                idDelta add
                cmapf2_glyph_array exch cmapf2_ch exch put
            } {
                pop
                % cmapf2_glyph_array cmapf2_ch 0 put
            } ifelse
        } {   % false: j is outside
            % cmapf2_glyph_array cmapf2_ch 0 put
        } ifelse
    } def

    16#00 1 16#ff { % hi_byte scan
        /cmapf2_ch_hi exch def
        sHKs cmapf2_ch_hi sHK_sz mul getu16
        /sH_offset exch def
        sH_gIA sH_offset sH_sz getinterval
            dup 0 getu16 /firstCode exch def
            dup 2 getu16 /entryCount exch def
            dup 4 gets16 /idDelta exch def
            dup 6 getu16 /idRangeOffset exch def
        pop
        sH_offset 0 eq {
           /cmapf2_ch_lo cmapf2_ch_hi def
           /cmapf2_ch_hi 0 def
           .cmapf2_putGID
        } {
           16#00 1 16#ff { % lo_byte scan
               /cmapf2_ch_lo exch def
               .cmapf2_putGID
           } for
        } ifelse
     } for
     pop
     0 1 cmapf2_glyph_array length 1 sub { % rewrite null -> 0.
        dup cmapf2_glyph_array exch get
        null eq { cmapf2_glyph_array exch 0 put } {pop} ifelse
     } for
     cmapf2_glyph_array
  } bind
  4 {           % Microsoft/Adobe segmented mapping.
    /etab exch def
    /nseg2 etab 6 getu16 def
    14 /endc etab 2 index nseg2 getinterval def
                % The Apple TrueType documentation omits the 2-byte
                % 'reserved pad' that follows the endCount vector!
    2 add
    nseg2 add /startc etab 2 index nseg2 getinterval def
    nseg2 add /iddelta etab 2 index nseg2 getinterval def
    nseg2 add /idroff etab 2 index nseg2 getinterval def
                % The following hack allows us to properly handle
                % idiosyncratic fonts that start at 0xf000:
    pop
    /firstcode startc 0 getu16 16#ff00 and dup 16#f000 ne { pop 0 } if def
    /striptopbyte false def
    /putglyph {
      glyphs code 3 -1 roll put /code code 1 add def
    } bind def
                % Do a first pass to compute the size of the glyphs array.
    /numcodes 0 def /glyphs 0 0 2 nseg2 3 sub {
                % Stack: /glyphs numglyphs i2
      /i2 exch def
      /scode startc i2 getu16 def
      /ecode endc i2 getu16 def
      ecode lastcode gt {
        /lastcode ecode def
      } if
    } for pop
    % If the glyph range is within 0x..00 to 0x..FF, make sure that we strip
    % off any top bytes.
    firstcode 16#f000 ge lastcode firstcode sub 255 le and {
      lastcode 255 and
      /striptopbyte true def
    } {
      lastcode
    }ifelse
    1 add
    array def
    % prefill the array with 0's faster than a { 0 putglyph } repeat
    glyphs length 1024 ge {
      .array1024z 0 1024 glyphs length 1023 sub { glyphs exch 2 index putinterval } for
      glyphs dup length 1024 sub 3 -1 roll
      putinterval
    } {
      0 1 glyphs length 1 sub { glyphs exch 0 put } for
    } ifelse
                % Now fill in the array.
    /numcodes 0 def /code 0 def
    0 2 nseg2 3 sub {
      /i2 exch def
      /scode startc i2 getu16 def
      /ecode endc i2 getu16 def
      numcodes scode firstcode sub
                % Hack for fonts that have only 0x0000 and 0xf000 ranges
      %dup 16#e000 ge { 255 and } if
      % the previous line is obstructive to CJK fonts, so it was removed
      exch sub 0 .max dup /code exch code exch add def
      ecode scode sub 1 add add numcodes add /numcodes exch def
      /delta iddelta i2 gets16 def
      TTFDEBUG {
        (scode=) print scode =only
        ( ecode=) print ecode =only
        ( delta=) print delta =only
        ( droff=) print idroff i2 getu16 =
      } if
      idroff i2 getu16 dup 0 eq {
        pop scode delta add 65535 and 1 ecode delta add 65535 and
        striptopbyte {
          /code scode 255 and def
        } {
          /code scode def
        } ifelse
        { putglyph } for
      } {       % The +2 is for the 'reserved pad'.
        /gloff exch 14 nseg2 3 mul add 2 add i2 add add def
        striptopbyte {
          /code scode 255 and def
        } {
          /code scode def
        } ifelse
        0 1 ecode scode sub {
          2 mul gloff add etab exch getu16
          dup 0 ne { delta add 65535 and } if putglyph
        } for
      } ifelse
    } for glyphs /glyphs null def       % for GC
  } bind
  6 {           % Single interval lookup.
    dup 6 getu16 /firstcode exch def dup 8 getu16 /ng exch def
    firstcode ng add array
                % Stack: tab array
                % Fill elements 0 .. firstcode-1 with 0
    0 1 firstcode 1 sub { 2 copy 0 put pop } for
    dup firstcode ng getinterval
                % Stack: tab array subarray
                % Fill elements firstcode .. firstcode+nvalue-1 with glyph values
    0 1 ng 1 sub {
      dup 2 mul 10 add 4 index exch getu16 3 copy put pop pop
    } for pop exch pop
  } bind
.dicttomark readonly def                % cmapformats

% <cmaptab> cmaparray <glypharray>
/cmaparray {
  dup 0 getu16 cmapformats exch .knownget {
    TTFDEBUG {
      (cmap: format ) print 1 index 0 getu16 = flush
    } if exec
  } {
    (Can't handle format ) print 0 getu16 = flush
    0 1 255 { } for 256 packedarray
  } ifelse
  TTFDEBUG {
    (cmap: length=) print dup length = dup ==
  } if
} bind def

% Define remapping for misnamed glyphs in TrueType 'post' tables.
% There are probably a lot more than this!
/postremap mark
  /Cdot /Cdotaccent
  /Edot /Edotaccent
  /Eoverdot /Edotaccent
  /Gdot /Gdotaccent
  /Ldot /Ldotaccent
  /Zdot /Zdotaccent
  /cdot /cdotaccent
  /edot /edotaccent
  /eoverdot /edotaccent
  /gdot /gdotaccent
  /ldot /ldotaccent
  /zdot /zdotaccent
.dicttomark readonly def

/get_from_stringarray % <array|string> <offset> get_from_stringarray <int>
{ 1 index type /stringtype eq {
    get
  } {
    exch {                % o ()
      2 copy length ge {
        length sub
      } {
        exch get exit
      } ifelse
    } forall
  } ifelse
} bind def

/getinterval_from_stringarray % <array|string> <offset> <length> getinterval_from_stringarray <string>
{ % May allocate a string in VM.
  2 index type /stringtype eq {
    getinterval
  } {
    string exch 0                                 % [] s o p
    4 3 roll {                                    % s o p Si
      dup length                                  % s o p Si lSi
      dup 4 index lt {
        3 index exch sub                          % s o p Si o'
        exch pop 3 1 roll exch pop                % s o' p
      } {                                         % s o p Si lSi
        dup 3 1 roll                              % s o p lSi Si lSi
        4 index sub                               % s o p lSi Si lSi-o
        5 index length 4 index sub                % s o p lSi Si lSi-o ls-p
        2 copy gt { exch } if pop                 % s o p lSi Si minl
        dup 3 1 roll                              % s o p lSi minl Si minl
        5 index exch getinterval                  % s o p lSi minl from
        5 index 4 index 3 index                   % s o p lSi minl from s p minl
        getinterval                               % s o p lSi minl from to
        copy pop                                  % s o p lSi minl
        exch pop add exch pop 0 exch              % s 0 p'
        dup 3 index length ge { exit } if
      } ifelse
    } forall
    pop pop                                       % s
  } ifelse
} bind def

/string_array_size  % <array|string> string_array_size <int>
    { dup type /stringtype eq {
    length
  } {
    0 exch { length add } forall
  } ifelse
} bind def

% Each procedure in this dictionary is called as follows:
%       posttable <<proc>> glyphencoding
/postformats mark
  16#00010000  {        % 258 standard Macintosh glyphs.
    pop MacGlyphEncoding
  }
  16#00020000  {        % Detailed map, required by Microsoft fonts.
    dup dup type /arraytype  eq { 0 get } if length 36 lt {
      TTFDEBUG { (post format 2.0 invalid.) = flush } if
      pop [ ]
    } {
      /postglyphs exch def
      /post_first postglyphs dup type /arraytype eq { 0 get } if def
      post_first 32 getu16 /numglyphs exch def
      /glyphnames numglyphs 2 mul 34 add def
      % Build names array in the order they occur in the 'post' table
      /postpos glyphnames def
      /total_length postglyphs //string_array_size exec def
      numglyphs array 0 1 numglyphs 1 sub {
    postpos total_length ge {
          % Fill the rest with .notdef
          1 numglyphs 1 sub { 1 index exch /.notdef put } for
          exit
        } if
    % No name available, /postnames will be defined as an empty
    % array and the glyph won't get a name attached.
    postglyphs postpos //get_from_stringarray exec
        postglyphs postpos 1 add 2 index //getinterval_from_stringarray exec cvn
    exch postpos add 1 add /postpos exch def
        2 index 3 1 roll
        put
      } for
      /postnames exch def
      numglyphs array 0 1 numglyphs 1 sub {
    dup 2 mul 34 add postglyphs exch 2 //getinterval_from_stringarray exec
    dup 0 get 8 bitshift exch 1 get add dup 258 lt {
      MacGlyphEncoding exch get
    } {
      dup 32768 ge {
        % According to the published TrueType spec, such values are
        % "reserved for future use", but at least some PDF files
        % produced by the Adobe PDF library contain entries with a
        % value of 16#ffff.
        pop /.notdef
      } {
        % Get the name for this glyph
        258 sub dup postnames length ge {
          TTFDEBUG { (   *** warning: glyph index past end of 'post' table) = flush } if
          pop
          exit
        } if
        postnames exch get
        % At least some of Microsoft's TrueType fonts use incorrect
        % (Adobe-incompatible) names for some glyphs.
        % Correct for this here.
        postremap 1 index .knownget { exch pop } if
      } ifelse
    } ifelse
    2 index 3 1 roll put
      } for

    }
    ifelse
  } bind
  16#00030000  {        % No map.
    pop [ ]
  } bind
.dicttomark readonly def                % postformats

/first_post_string % - first_post_string <string>
{
  post dup type /arraytype eq { 0 get } if
} bind def

% - .getpost -
% Uses post, defines glyphencoding
/.getpost {
  /glyphencoding post null eq {
    TTFDEBUG { (post missing) = flush } if [ ]
  } {
    postformats first_post_string 0 getu32 .knownget {
      TTFDEBUG {
        (post: format ) print
        first_post_string
        dup 0 getu16 =only (,) print 2 getu16 = flush
      } if
      post exch exec
    } {
      TTFDEBUG { (post: unknown format ) print post 0 getu32 = flush } if [ ]
    } ifelse
  } ifelse def
} bind def

% ===================== True Type Interpretation =============

/TTParser <<
  /Pos 0
  /post null
>> def

/readu8   % <file> readu8 <int>
{ read not {
    mark (Insufficient data in the stream.) //error exec
  } if
} bind def

/readu16   % <file> readu16 <int>
{ dup //readu8 exec 8 bitshift exch //readu8 exec or
} bind def

/reads16   % <file> reads16 <int>
{ //readu16 exec 16#8000 xor 16#8000 sub
} bind def

/readu32   % <file> readu32 <int>
{ dup //readu16 exec 16 bitshift exch //readu16 exec or
} bind def

/reads32   % <file> reads32 <int>
{ dup //reads16 exec 16 bitshift exch //readu16 exec or
} bind def

/SkipToPosition % <file> <int> SkipToPosition -
{ dup //TTParser /Pos get                               % f P P p
  exch //TTParser exch /Pos exch put                    % f P p
  sub                                                   % f P-p
  //PDFR_DEBUG {
    (Skipping ) print dup //=only exec ( bytes.) =
  } if
  dup 0 eq {
    pop pop
  } {
    dup 3 1 roll                                        % P-p f P-p
    () /SubFileDecode filter                            % P-p f'
    exch                                                % f' P-p
    { 1 index //BlockBuffer readstring pop length
      dup 0 eq { pop exch pop exit } if
      sub
    } loop
    0 ne {
      mark (Insufficient data in the stream for SkipToPosition.) //error exec
    } if
  } ifelse
} bind def

/TagBuffer 4 string def

/ParseTTTableDirectory  % <file> ParseTTTableDirectory <dict>
{ //PDFR_DEBUG {
    (ParseTTTableDirectory beg) =
  } if
  15 dict begin
    dup //readu32 exec 16#00010000 ne {
      mark (Unknown True Type version.) //error exec
    } if
    dup //readu16 exec /NumTables exch def
    dup //readu16 exec /SearchRange exch def
    dup //readu16 exec /EntrySelector exch def
    dup //readu16 exec /RangeShift exch def
    //PDFR_DEBUG {
      (NumTables = ) print NumTables =
    } if
    NumTables {
      dup //TagBuffer readstring not {
        mark (Could not read TT tag.) //error exec
      } if
      cvn
      [ 2 index //readu32 exec pop % CheckSum
        2 index //readu32 exec  % Offset
        3 index //readu32 exec  % Length
      ]
      //PDFR_DEBUG {
        2 copy exch //=only exec ( ) print ==
      } if
      def
    } repeat
    pop  % file
    //TTParser /Pos 12 NumTables 16 mul add put
  currentdict end
  //PDFR_DEBUG {
    (ParseTTTableDirectory end) =
  } if
} bind def

/ParseTTcmap  % <file> <TableDirectory> ParseTTcmap <dict>
{ //PDFR_DEBUG {
    (ParseTTcmap beg) =
  } if
  /cmap get aload pop                                   % f o L
  3 1 roll                                              % L f o
  7 dict begin
    //PDFR_DEBUG {
      (Current position = ) print //TTParser /Pos get =
      (cmap position = ) print dup =
    } if
    1 index exch //SkipToPosition exec                  % L f
    //TTParser /Pos get /TablePos exch def
    dup //readu16 exec pop % version
    dup //readu16 exec /NumEncodings exch def
    //PDFR_DEBUG {
      (NumEncodings = ) print NumEncodings =
    } if
    null                                                % L f null
    NumEncodings {
      1 index //readu32 exec % platformID, specificID   % L f null id
      2 index //readu32 exec % offset                   % L f null id o
      3 array dup 3 2 roll 0 exch put                   % L f []|null id []
      2 index null ne {
        dup 0 get 3 index 0 get sub                     % L f []|null id [] l
        3 index exch 1 exch put                         % L f []|null id []
      } if
      dup 4 3 roll pop 3 1 roll                         % L f [] id []
      def
    } repeat                                            % L f []
    dup 0 get                                           % L f [] o
    4 3 roll exch sub                                   % f [] L-o
    1 exch put                                          % f
    //PDFR_DEBUG {
      currentdict {
        exch dup type /integertype eq {
          //PrintHex exec ( ) print ==
        } {
          pop pop
        } ifelse
      } forall
    } if
    4 NumEncodings 8 mul add /HeaderLength exch def
    //TTParser /Pos //TTParser /Pos get HeaderLength add put
    0                                                  % f o
    NumEncodings {
      16#7FFFFFF null                                  % f o om null|[]
      % Choosing a table with minimal offset greater than 'o' :
      currentdict {
        1 index type /integertype eq {                 % f o om null|[] id []
          exch pop dup 0 get                           % f o om null|[] [] oi
          dup 5 index gt {
            dup 4 index lt {
              4 1 roll                                 % f o oi om null|[] []
              exch pop exch pop                        % f o oi []
            } {
              pop pop
            } ifelse
          } {
            pop pop
          } ifelse                                     % f o oi []
        } {
          pop pop
        } ifelse
      } forall                                         % f o om' []
      //PDFR_DEBUG {
        (Obtaining subtable for ) print dup ==
      } if
      3 2 roll pop                                     % f o' []
      3 copy pop                                       % f o' [] f o'
      TablePos add //SkipToPosition exec               % f o' []
      3 copy exch pop 1 get                            % f o' [] l
      //TTParser /Pos //TTParser /Pos get 3 index add put
      string                                           % f o' [] f ()
      readstring not {
        mark (Can't read a cmap subtable.) //error exec
      } if                                             % f o' [] ()
      2 exch put                                       % f o'
    } repeat
    pop pop                                            %
  currentdict end
  //PDFR_DEBUG {
    (ParseTTcmap end) =
  } if
} bind def

/GetTTEncoding   % <file> <TTcmapHeader> <platformIDspecificID> GetTTEncoding <array>
{ //PDFR_DEBUG {
    (GetTTEncoding beg) =
  } if
  get                                      % f []
  exch pop                                 % []
  2 get
  10 dict begin % For local variables.
    /TTFDEBUG //PDFR_DEBUG def
    //cmaparray exec
  end
  //PDFR_DEBUG {
    (GetTTEncoding end) =
    dup ==
  } if
} bind def

/InverseEncoding % <encoding> InverseEncoding <dict>
{
  256 dict begin
    dup length 1 sub -1 0 {                       % E i
      2 copy get                                  % E i n
      exch                                        % E n i
      1 index currentdict exch //knownget exec {  % E n i e
        dup type /arraytype eq {
          aload length 1 add array astore         % E n e'
        } {
          2 array astore                          % E n e'
        } ifelse
      } if
      def
    } for
    pop
   currentdict end
} bind def

/GetMacRomanEncodingInverse
{ //PDFReader /MacRomanEncodingInverse get
  dup null eq {
    pop
    MacRomanEncoding //InverseEncoding exec
    dup //PDFReader exch /MacRomanEncodingInverse exch put
  } if
} bind def

/PutCharStringSingle    % <cmap_array> <glyph_name> <char_code> PutCharStringSingle  <cmap_array>
{
  dup 3 index length lt {                               % cmap name code
    2 index exch get                                    % cmap name glyphindex
    dup 0 ne {
      def                                               % cmap
    } {
      pop pop
    } ifelse
  } {
    pop pop                                             % cmap
  } ifelse
} bind def

/PutCharString  % <cmap_array> <glyph_name> <char_code> PutCharString  <cmap_array>
{ 1 index type /nametype ne {
    mark (Bad charstring name) //error exec
  } if
  dup type /arraytype eq {
    {                                                   % cmap name code
      3 copy //PutCharStringSingle exec                 % cmap name code cmap
      pop pop                                           % cmap name
    } forall
    pop                                                 % cmap
  } {
    //PutCharStringSingle exec
  } ifelse
} bind def

/ComposeCharStrings % <cmaparray> <dict> ComposeCharStrings <dict>
{
  //PDFR_DEBUG {
    (ComposeCharStrings beg) =
  } if
  1 index length 1 add dict begin                       % cmap d
  % fixme : the dict length estimation doesn't account 'post'.
  /.notdef 0 def
  exch                                                  % d cmap
  //TTParser /post get                                  % d cmap [post]|null
  dup null ne {
    exch                                                % d [] cmap
    1 index length 1 sub -1 0 {                         % d [] cmap code
      dup 3 index exch get exch                         % d [] cmap name code
      dup 0 eq 2 index /.notdef eq or {			% do not re-encode GID 0, or the
                                                        % /.notdef glyph name
        pop pop
      } {
        def
      } ifelse
    } for
  } if
  exch pop exch                                         % cmap d
  {                                                     % cmap name code
    //PutCharString exec
  } forall                                              % cmap
  pop                                                   %
  currentdict end
  //PDFR_DEBUG {
    (ComposeCharStrings end) =
  } if
} bind def

/ParseTTpost   % <file> <TableDirectory> ParseTTpost -
{ % Defines TTparser.post - an array,
  % which maps glyph indices to glyph names.
  //PDFR_DEBUG {
    (ParseTTpost beg) =
  } if
  /post get aload pop                                   % f o L
  3 1 roll                                              % L f o
  //PDFR_DEBUG {
    (Current position = ) print //TTParser /Pos get =
    (post position = ) print dup =
  } if
  1 index exch //SkipToPosition exec                    % L f
  //TTParser /Pos //TTParser /Pos get 4 index add put
  exch dup 65535 le {
    string                                              % f s
    readstring not {
      mark (Insufficient data in the stream for ParseTTpost.) //error exec
    } if                                                % s
  } {
                                    % f s
      [ 3 1 roll                    % [ f s
      dup 16384 div floor cvi       % [ f s numblocks
      exch 1 index 16384 mul        % [ f numblocks s bytesinblocks
      sub exch                      % [ f remainder numblocks
      1 sub 0 1 3 -1 roll           % [ f remainder 0 1 numblocks
      {
        1 add index                 % [ f remainder () ()... f
        16384 string readstring not {
          mark (Insufficient data in the stream for ParseTTpost.) //error exec
        } if
      } for
                                    % [ f remainder () ()...
      counttomark -2 roll           % [ () ()... f remainder
      string readstring not{
        mark (Insufficient data in the stream for ParseTTpost.) //error exec
      } if
      ]
  } ifelse
  1 dict begin % A bridge to the code from /gs/lib/gs_ttf.ps .
    /post exch def
    //.getpost exec
    //TTParser /post glyphencoding put
    //PDFR_DEBUG {
      (ParseTTpost end) =
      glyphencoding ==
    } if
  end
} bind def

/MakeTTCharStrings % <FontFile_object> MakeTTCharStrings <CharStrings>
{ //MakeStreamReader exec                               % f
  dup dup //ParseTTTableDirectory exec                  % f f d
  % Since the file isn't positionable,
  % we must pick up either 'post' or 'cmap' first.
  % Deside which one we do first :
  //TTParser /post null put
  dup /post //knownget exec {
    0 get
    1 index /cmap get 0 get
    lt {
      2 copy //ParseTTpost exec                         % f f d
      //ParseTTcmap exec                                % f ch
    } {
      2 copy //ParseTTcmap exec                         % f f d ch
      3 1 roll                                          % f ch f d
      //ParseTTpost exec                                % f ch
    } ifelse
  } {
    //ParseTTcmap exec                                  % f ch
  } ifelse
  {
    dup 16#00030001 known {
      //PDFR_DEBUG {
        (Using the TT cmap encoding for Windows Unicode.) =
      } if
      16#00030001 //GetTTEncoding exec
      AdobeGlyphList //ComposeCharStrings exec
      exit
    } if
    dup 16#00010000 known {
      //PDFR_DEBUG {
        (Using the TT cmap encoding for Macintosh Roman.) =
      } if
      16#00010000 //GetTTEncoding exec
      PDFEncoding dup null eq {
        pop //GetMacRomanEncodingInverse exec
      } {
        //InverseEncoding exec
      } ifelse
      //ComposeCharStrings exec
      exit
    } if
    dup 16#00030000 known {
      //PDFR_DEBUG {
        (Using the TT cmap encoding 3.0 - not sure why Ghostscript writes it since old versions.) =
      } if
      % Same algorithm as for 16#00010000.
      16#00030000 //GetTTEncoding exec
      PDFEncoding dup null eq {
        pop //GetMacRomanEncodingInverse exec
      } {
        //InverseEncoding exec
      } ifelse
      //ComposeCharStrings exec
      exit
    } if
    mark (True Type cmap has no useful encodings.) //error exec
  } loop
  //PDFR_DEBUG {
    (CharStrings <<) =
    dup {
      exch
      dup type /nametype eq {
        //=only exec
      } {
        ==
      } ifelse
      ( ) print ==
    } forall
    (>>) =
  } if
} bind def

%%end TrueType

% ===================== Functions ============================

/ScaleVal % <value> <Range> ScaleVal <scaled_value>
{
  aload pop                                             % v r0 r1
  1 index sub                                           % v r0 r1-r0
  3 2 roll mul add
} bind def

/ScaleArg % <arg> <Domain> ScaleArg <scaled_arg>
{
  aload pop                                             % a d0 d1
  1 index sub                                           % a d0 d1-d0
  3 1 roll                                              % d1-d0 a d0
  sub exch div                                          % (a-d0)/(d1-d0)
} bind def

/ScaleArgN % <arg1> ... <argN> <Domain> ScaleArg <scaled_arg1> ... <scaled_argN>
{
  dup length 2 sub -2 0 {                               % a1 ... an [] 2i
    2                                                   % a1 ... an [] 2i 2
    2 index 3 1 roll getinterval                        % a1 ... an [] []
    3 2 roll                                            % a1 ... [] [] an
    exch //ScaleArg exec                                % a1 ... [] an'
    1 index length 2 idiv 1 add 1 roll                  % an' a1 ... []
  } for                                                 % a1' ... an' []
  pop                                                   % a1' ... an'
} bind def


/ComputeFunction_10 % <scaled_arg> <sample_array> ComputeFunction_10 <result>
{ % Assuming a 1-argument 1-result function type 0.
  //PDFR_DEBUG {
    (ComputeFunction_10 beg ) print 1 index //=only exec ( stack=) print count =
  } if
  exch                                                  % [] x
  dup 1 eq {
    pop dup length 1 sub get                            % y
  } {
    1 index length 1 sub mul                            % [] x*(l-1)
    dup dup floor sub                                   % [] x*(l-1) f
    dup 0 eq {
      pop cvi get                                       % y
    } {
      3 1 roll floor cvi                                % f [] i
      2 getinterval                                     % f []
      aload pop                                         % f y0 y1
      2 index mul 3 2 roll 1 exch sub 3 2 roll mul add  % y1*f+(1-f)*y0
    } ifelse
  } ifelse
  //PDFR_DEBUG {
    (ComputeFunction_10 end ) print dup //=only exec ( stack=) print count =
  } if
} bind def

/ComputeFunction_n0 % <arg1> .... <argn> <sample_array> <n> ComputeFunction_n0 <result>
{ % Assuming a n-argument 1-result function type 0.
  //PDFR_DEBUG {
    (ComputeFunction_n0 beg N=) print dup //=only exec ( stack=) print count =
  } if
  dup 0 eq {                                   % v 0
    pop                                        % v
  } {
    dup 2 add -1 roll                          % a2 .... an [] n a1
    dup 3 index length 1 sub ge {
      pop 1 sub                                % a2 .... an [] n-1
      exch dup length 1 sub get exch
      //PDFReader /ComputeFunction_n0 get exec
    } {
      dup floor cvi dup                        % a2 .... an [] n a1 i i
      4 index exch get                         % a2 .... an [] n a1 i [i]
      3 index dup                              % a2 .... an [] n a1 i [i] n n
      5 add copy                               % a2 .... an [] n a1 i [i] n a2 .... an [] n a1 i [i] n
      6 2 roll                                 % a2 .... an [] n a1 i [i] n a2 .... an [i] n [] n a1 i
      pop pop pop pop                          % a2 .... an [] n a1 i [i] n a2 .... an [i] n
      1 sub                                    % a2 .... an [] n a1 i [i] n a2 .... an [i] n-1
      //PDFReader /ComputeFunction_n0 get exec % a2 .... an [] n a1 i [i] n v0
      3 2 roll pop                             % a2 .... an [] n a1 i n v0
      exch                                     % a2 .... an [] n a1 i v0 n
      4 3 roll exch                            % a2 .... an [] n i v0 a1 n
      4 add 2 roll 1 add                       % v0 a1 a2 .... an [] n i+1
      3 2 roll exch get                        % v0 a1 a2 .... an n [i+1]
      exch 1 sub                               % v0 a1 a2 .... an [i+1] n-1
      //PDFReader /ComputeFunction_n0 get exec % v0 a1 v1
      1 index mul                              % v0 a1 v1*a1
      3 1 roll                                 % v1*a1 v0 a1
      1 exch sub mul add                       % v1*a1+v0*(1-a1)
    } ifelse
  } ifelse
  //PDFR_DEBUG {
    (ComputeFunction_n0 end ) print dup //=only exec ( stack=) print count =
  } if
} bind def

/FunctionToProc_x01 % <function_dict> FunctionToProc_x01 <proc>
{ % Assuming a n-argument 1-result function type 0.
  % The stream is already converted to the array /Data.
  dup /Domain get exch
  dup /Data get 0 get exch
  /Size get length
  [ 4 1 roll
    //PDFR_DEBUG {
      { (function beg, stack =) print count //=only exec (\n) print } /exec load
      5 2 roll
    } if
    dup 1 gt {                                 % a1 ... an Domain Data n
      { mark exch                              % a1 ... an Domain Data [ n
        3 add 2 roll                           % Data [ a1 ... an Domain
        //ScaleArgN exec                       % Data [ a1 ... an
        counttomark dup                        % Data [ a1 ... an n n
        3 add -2 roll                          % a1 ... an n Data [
        pop exch                               % a1 ... an Data n
        //ComputeFunction_n0 exec
      } /exec load
    } {
      pop                                      % a1 Domain Data
      3 1 /roll load //ScaleArg /exec load     % Data a1s
      /exch load
      //ComputeFunction_10 /exec load
    } ifelse
    //PDFR_DEBUG {
      (function end, stack =) /print load /count load //=only /exec load (\n) /print load
    } if
  ] cvx
  //PDFR_DEBUG {
    (Made a procedure for the 1-result function :) =
    dup ==
  } if
} bind def

/FunctionProcDebugBeg  %  - FunctionProcDebugBeg -
{ (FunctionProcDebugBeg ) print count =
} bind def

/FunctionProcDebugEnd  %  - FunctionProcDebugEnd -
{ (FunctionProcDebugEnd ) print count =
} bind def

/FunctionToProc_x0n % <function_dict> <m> FunctionToProc_x0n <proc>
{ % Assuming a n-argument m-result function type 0.
  % The stream is already converted to the array /Data.
  %
  % Making the procedure : { Domain //ScaleArg exec ... n copy {} exec n+1 1 roll ... }
  % except "n copy" for the last chunk.
  %
  PDFR_DEBUG {
    (FunctionToProc_x0n beg m=) print dup =
  } if
  1 index /Size get length exch                         % f n m
  dup 7 mul 2 add array                                 % f n m []
  PDFR_DEBUG {
    dup 0 //FunctionProcDebugBeg put
  } {
    dup 0 //DoNothing put
  } ifelse
  dup 1 /exec load put
  dup 2 5 index /Domain get put
  2 index 1 eq {
    dup 3 //ScaleArg put
  } {
    dup 3 //ScaleArgN put
  } ifelse
  dup 4 /exec load put
  1 index 1 sub 0 exch 1 exch {                         % f n m [] i
    dup 7 mul 5 add                                     % f n m [] i i1
    1 index 4 index 1 sub ne {
      dup 3 index exch 6 index put 1 add
      dup 3 index exch /copy load put 1 add
    } if
    [                                                   % f n m [] i i1 [
      6 index /Data get 3 index get                     % f n m [] i i1 [ di
      6 index 1 eq {
        //ComputeFunction_10 /exec load
      } {
        6 index
        //ComputeFunction_n0 /exec load
      } ifelse
    ] cvx                                               % f n m [] i i1 {}
    3 index exch 2 index exch put 1 add                 % f n m [] i i1
    2 index 1 index /exec load put 1 add
    1 index 4 index 1 sub ne {
      2 index 1 index 6 index 1 add put 1 add
      2 index 1 index 1 put 1 add
      2 index 1 index /roll load put                    % f n m [] i i1
    } if
    pop pop                                             % f n m []
  } for
  PDFR_DEBUG {
    dup dup length 2 sub //FunctionProcDebugEnd put
  } {
    dup dup length 2 sub //DoNothing put
  } ifelse
  dup dup length 1 sub /exec load put
  cvx exch pop exch pop exch pop
  //PDFR_DEBUG {
    (Made a procedure for the n-argument function :) =
    dup ==
  } if
  PDFR_DEBUG {
    (FunctionToProc_x0n end) =
  } if
} bind def

/MakeTableRec % <func_obj> <n> MakeTableRec <array>
{
  0 % to be bound below
  exec
} bind def

/MakeTable % <func_obj> <n> MakeTable <array>
{ //PDFR_DEBUG {
    (MakeTable beg ) print count =
  } if
  1 index /Size get exch                                % f S N
  1 sub dup                                             % f S n n
  3 1 roll                                              % f n S n
  get                                                   % f n s
  array                                                 % f n []
  1 index 0 eq {
    exch pop exch pop                                   % []
  } {
    dup length 1 sub -1 0 {                             % f n [] i
      3 index 3 index //MakeTableRec exec               % f n [] i []
      2 index 3 1 roll put                              % f n []
    } for
    exch pop exch pop
  } ifelse
  //PDFR_DEBUG {
    (MakeTable end ) print count =
  } if
} bind def

//MakeTableRec 0 //MakeTable put

/StoreSample  % <value> <table> <dimensions> StoreSample -
{ % The reader is on the dictionary stack.
  1 sub
  dup 0 eq {
    pop                                                 % v []
  } {
    -1 1 {                                              % v T i
      I exch get get                                    % v T[I[i]]
    } for                                               % v []
  } ifelse
  I 0 get 3 2 roll put
} bind def

/ReadSample32   % - ReadSample32 <value>
{
  4 {
    File read not {
      mark (Insufficient data for function.) //error exec
    } if
  } repeat
  pop % Ignore the last byte because it can't fit into 'real'.
  3 1 roll exch
  256 mul add 256 mul add
  //1_24_bitshift_1_sub div
} bind def

/ReadSample   % - ReadSample <value>
{ % The reader in on the dictionary stack.
  Buffer BitsLeft BitsPerSample
  { 2 copy ge {
      exit
    } if
    3 1 roll
    8 add 3 1 roll
    256 mul File read not {
      mark (Insufficient data for function.) //error exec
    } if
    add
    3 1 roll
  } loop                                                % b bl pbs
  sub dup                                               % b bl-bps bl-bps
  2 index exch                                          % b bl-bps b bl-bps
  neg bitshift                                          % b bl-bps v
  2 copy exch bitshift                                  % b bl-bps v v<<(bl-bps)
  4 3 roll exch sub                                     % bl-bps v b-(v<<(bl-bps))
  /Buffer exch def                                      % bl-bps v
  exch /BitsLeft exch def                               % v
  Div div                                               % v/(1<<pbs-1)
} bind def

/ReadSamplesRec % <dimensions> ReadSamplesRec -
{ 0 % Will be bound below
  exec
} bind def

/ReadSamples % <dimensions> ReadSamples -
{ % The reader in on the dictionary stack.
  //PDFR_DEBUG {
    (ReadSamples beg ) print count =
  } if
  dup 1 eq {
    pop
    0 1 Size 0 get 1 sub {
      I exch 0 exch put
      0 1 M 1 sub {
        dup Range exch 2 mul 2 getinterval              % m r
        //PDFR_DEBUG {
          (Will read a sample ... ) print
        } if
        BitsPerSample 32 eq { //ReadSample32 } { //ReadSample } ifelse
        exec exch //ScaleVal exec                       % m v
        //PDFR_DEBUG {
          (value=) print dup =
        } if
        exch Table exch get                             % v []
        Size length //StoreSample exec                  %
      } for
    } for
  } {
    1 sub
    dup Size exch get 0 exch 1 exch 1 sub {             % d-1 i
      I exch 2 index exch put                           % d-1
      dup //ReadSamplesRec exec                         % d-1
    } for
    pop
  } ifelse
  //PDFR_DEBUG {
    (ReadSamples end ) print count =
  } if
} bind def

//ReadSamplesRec 0 //ReadSamples put

/StreamToArray % <obj> StreamToArray -
{ //PDFR_DEBUG {
    (StreamToArray beg ) print count =
  } if
  userdict /FuncDataReader get begin                    % f
    dup /BitsPerSample get /BitsPerSample exch def
    dup /Size get length /N exch def
    dup /Range get length 2 idiv /M exch def
    1 BitsPerSample bitshift 1 sub /Div exch def
    /BitsLeft 0 def
    /Buffer 0 def
    dup /Size get /Size exch def                        % f
    dup /Range get /Range exch def                      % f
    /File 1 index //MakeStreamReader exec def           % f
    /I [ N { 0 } repeat ] def                           % f
    M array                                             % f []
    dup length 1 sub -1 0 {                             % f [] m
      2 index N //MakeTable exec                        % f [] m T
      2 index 3 1 roll put                              % f []
    } for
    /Table exch def                                     % f
    N //ReadSamples exec                                % f
    PDFR_DEBUG {
      (Table = ) print Table ==
    } if
    /Data Table put                                     %
  end
  //PDFR_DEBUG {
    (StreamToArray end ) print count =
  } if
} bind def

/FunctionToProc10 % <function_dict> FunctionToProc10 <proc>
{ % Assuming a 1-argument function type 0.
  PDFR_DEBUG {
    (FunctionToProc10 beg, Range = ) print dup /Range get ==
  } if
  dup /Order //knownget exec {
    1 ne {
      (Underimplemented function Type 0 Order 3.) =
    } if
  } if
  dup //StreamToArray exec                              % f
  dup /Range get length dup 2 eq {
    pop //FunctionToProc_x01 exec                       % proc
  } {
    2 idiv //FunctionToProc_x0n exec                    % proc
  } ifelse
  PDFR_DEBUG {
    (FunctionToProc10 end) =
  } if
} bind def

/FunctionToProc12 % <function_dict> FunctionToProc12 <proc>
{ begin
    currentdict /C0 //knownget exec { length 1 eq } { true } ifelse {
      N
      currentdict /C0 //knownget exec {
        0 get
      } {
        0
      } ifelse
      currentdict /C1 //knownget exec {
        0 get
      } {
        1
      } ifelse
      1 index sub
      [ 4 1 roll
        {               % x n c0 c1-c0
          4 2 roll      % c0 c1-c0 x n
          excp mul add  % y
        } aload pop
      ] cvx
    } {
        [
          0 1 C0 length 1 sub {
            N                                           % [ ... i n
            C0 2 index get                              % [ ... i n c0
            C1 3 index get                              % [ ... i n c0 c1
            4 3 roll pop                                % [ ... n c0 c1
            1 index sub                                 % [ ... n c0 c1-c0
            [ /dup load                                 % [ ... n c0 c1-c0 [ dup
              5 2 roll                                  % [ ... [ dup n c0 c1-c0
              {                 % x x n c0 c1-c0
                4 2 roll        % x c0 c1-c0 x n
                exp mul add     % x y
                exch            % y x
              } aload pop
            ] cvx
            /exec load
          } for
          /pop load
        ] cvx
    } ifelse
  end
  //PDFR_DEBUG {
    (FunctionType2Proc : ) print dup ==
  } if
} bind def


/FunctionToProc14 % <function_dict> FunctionToProc14 <proc>
{ //MakeStreamReader exec cvx exec
  //PDFR_DEBUG {
    (FunctionType4Proc : ) print dup ==
  } if
} bind def

/FunctionToProc1 % <function_dict> FunctionToProc <proc>
{ % Assuming a 1-argument function.
  dup /FunctionType get
  { dup 0 eq {
      pop //FunctionToProc10 exec exit
    } if
    dup 2 eq {
      pop //FunctionToProc12 exec exit
    } if
    dup 4 eq {
      pop //FunctionToProc14 exec exit
    } if
    mark exch (Function type ) exch ( isn't implemented yet.) //error exec
  } loop
} bind def

/FunctionToProc20 % <function_dict> FunctionToProc20 <proc>
{ % Assuming a 2-argument function type 0.
  PDFR_DEBUG {
    (FunctionToProc20, Range = ) print dup /Range get ==
  } if
  dup /Order //knownget exec {
    1 ne {
      (Underimplemented function Type 0 Order 3.) =
    } if
  } if
  dup //StreamToArray exec                              % f
  dup /Range get length dup 2 eq {
    pop //FunctionToProc_x01 exec                       % proc
  } {
    2 idiv //FunctionToProc_x0n exec                    % proc
  } ifelse
} bind def

/FunctionToProc % <function_dict> FunctionToProc <proc>
{ //PDFR_DEBUG {
    (FunctionToProc beg ) print count =
  } if
  dup type /dicttype eq {
    dup /Domain get length 2 idiv
    {
      dup 1 eq {
        pop //FunctionToProc1 exec exit
      } if
      dup 2 eq {
        pop //FunctionToProc20 exec exit
      } if
      mark (Functions with many arguments aren't implemented yet.) //error exec
    } loop
  } {
    //PDFR_DEBUG {(Not a function dict, assume already a procedure.) print } if
  } ifelse
  //PDFR_DEBUG {
    (FunctionToProc end ) print count =
  } if
} bind def

/spotfunctions mark  % Copied from pdf_draw.ps
  /Round {
    abs exch abs 2 copy add 1 le {
      dup mul exch dup mul add 1 exch sub
    } {
      1 sub dup mul exch 1 sub dup mul add 1 sub
    } ifelse
  }
  /Diamond {
    abs exch abs 2 copy add .75 le {
      dup mul exch dup mul add 1 exch sub
    } {
      2 copy add 1.23 le {
        .85 mul add 1 exch sub
      } {
        1 sub dup mul exch 1 sub dup mul add 1 sub
      } ifelse
    } ifelse
  }
  /Ellipse {
    abs exch abs 2 copy 3 mul exch 4 mul add 3 sub dup 0 lt {
      pop dup mul exch .75 div dup mul add 4 div 1 exch sub
    } {
      dup 1 gt {
        pop 1 exch sub dup mul exch 1 exch sub
        .75 div dup mul add 4 div 1 sub
      } {
        .5 exch sub exch pop exch pop
      } ifelse
    } ifelse
  }
  /EllipseA { dup mul .9 mul exch dup mul add 1 exch sub }
  /InvertedEllipseA { dup mul .9 mul exch dup mul add 1 sub }
  /EllipseB { dup 5 mul 8 div mul exch dup mul exch add sqrt 1 exch sub }
  /EllipseC { dup mul .9 mul exch dup mul add 1 exch sub }
  /InvertedEllipseC { dup mul .9 mul exch dup mul add 1 sub }
  /Line { exch pop abs neg }
  /LineX { pop }
  /LineY { exch pop }
  /Square { abs exch abs 2 copy lt { exch } if pop neg }
  /Cross { abs exch abs 2 copy gt { exch } if pop neg }
  /Rhomboid { abs exch abs 0.9 mul add 2 div }
  /DoubleDot { 2 {360 mul sin 2 div exch } repeat add }
  /InvertedDoubleDot { 2 {360 mul sin 2 div exch } repeat add neg }
  /SimpleDot { dup mul exch dup mul add 1 exch sub }
  /InvertedSimpleDot { dup mul exch dup mul add 1 sub }
  /CosineDot { 180 mul cos exch 180 mul cos add 2 div }
  /Double { exch 2 div exch 2 { 360 mul sin 2 div exch } repeat add }
  /InvertedDouble {
    exch 2 div exch 2 { 360 mul sin 2 div exch } repeat add neg
  }
.dicttomark readonly def

% ===================== Color Spaces and Colors ==============

/CheckColorSpace %  <key> <val> CheckColorSpace  <key> <val>
{
  dup type /arraytype ne {
    mark (Resource ) 3 index ( must be an array.) //error exec
  } if
} bind def

/SubstitutePDFColorSpaceRec  % <array> SubstitutePDFColorSpace <array>
{ 0 % Will be bound below
  exec
} bind def

/SubstitutePDFColorSpace % <array> SubstitutePDFColorSpace <array>
{
  {
    dup 0 get /Pattern eq {
      dup length 1 gt {
        dup dup 1 //CheckColorSpace //ResolveA exec
        dup type /nametype ne {
          //SubstitutePDFColorSpaceRec exec
        } if
        1 exch put
      } if
      exit
    } if
    dup 0 get /Indexed eq {
      exit
    } if
    dup 0 get /Separation eq {
      dup dup 2 //CheckColorSpace //ResolveA exec
      dup type /nametype ne {
        //SubstitutePDFColorSpaceRec exec
      } if
      2 exch put
      exit
    } if
    dup 0 get /CalGray eq {
      1 get                                             % dict
      dup /Gamma //knownget exec {
        [ exch [ exch /exp load ] cvx dup dup ]
        1 index exch /DecodeLMN exch put
      } if
      [ exch /CIEBasedA exch ]                          % []
      exit
    } if
    dup 0 get /CalRGB eq {
      1 get                                             % dict
      dup /Matrix //knownget exec {
        1 index exch /MatrixLMN exch put
      } if
      dup /Gamma //knownget exec {
        aload pop
        [ exch /exp load ] cvx
        3 1 roll
        [ exch /exp load ] cvx
        3 1 roll
        [ exch /exp load ] cvx
        3 1 roll
        3 array astore
        1 index exch /DecodeLMN exch put
      } if
      [ exch /CIEBasedABC exch ]                        % []
      exit
    } if
    dup 0 get /Lab eq {
      1 get                                             % dict
      begin
        currentdict /Range //knownget exec { aload pop } { -100 100 -100 100 } ifelse
          0 100 6 2 roll 6 array astore
          /RangeABC exch def
        /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind] def
        /MatrixABC [1 1 1 1 0 0 0 0 -1] def
        { dup 6 29 div ge {dup dup mul mul} {4 29 div sub 108 841 div mul} ifelse }
        /DecodeLMN [
          % Store white point implicitly inside procedures.
          [ 3 index aload pop WhitePoint 0 get /mul load ] cvx
          [ 4 index aload pop WhitePoint 1 get /mul load ] cvx
          [ 5 index aload pop WhitePoint 2 get /mul load ] cvx
        ] def pop
        //PDFR_DEBUG {
          (Constructed from Lab <<) =
          currentdict { exch = == } forall
          (>>) =
        } if
        [ /CIEBasedABC currentdict ]                    % []
      end
      exit
      pop
    } if
    % Check if this is an already substituted space
    dup 0 get /CIEBasedA eq {exit} if
    dup 0 get /CIEBasedABC eq {exit} if
    mark exch (Unimplemented color space ) exch //error exec
  } loop
} bind def

//SubstitutePDFColorSpaceRec 0 //SubstitutePDFColorSpace put

/ResolveArrayElement  % <array> <index> ResolveArrayElement <array>
{ 2 copy get
  dup type dup /arraytype eq exch
  /packedarraytype eq or {             % make sure its a procedure/executable array
    xcheck {
      2 copy get		       % Get executable array
      dup 0 get type /integertype eq   % ensure first element is an integer
      1 index 1 get type dup /arraytype
      eq exch
      /packedarraytype eq or           % ensure second element is executable array
      and {
          exec
          2 index 4 1 roll put
        } {
          pop pop
      } ifelse
    } {
      pop
    } ifelse
  } {
    pop pop
  } ifelse
} bind def

/ResolveColorSpaceArrayRec  % <color_space> ResolveColorSpaceArrayRec <color_space>
{ 0 % Will be bond below.
  exec
} bind def

/SetColorSpaceSafe % <color_space> SetColorSpaceSafe -
{
  % This works against applying a pattern over a pattern space,
  % which may happen due to duplication of stroking and non-stroking colors.
  % gs3.70 fails when setting a pattern space and
  % the (old) current color space is a pattern space.
  %
  % If the new color space is an array and it appears equal to the old one,
  % do nothing. Otherwise set the new color space.
  PDFR_DEBUG {
    (SetColorSpaceSafe beg) =
  } if
  currentcolorspace dup type /arraytype eq {     % cs cs'
    1 index type /arraytype eq {
      dup length 2 index length eq {
        false exch                               % cs b cs'
        dup length 0 exch 1 exch 1 sub {         % cs b cs' i
          dup                                    % cs b cs' i i
          4 index exch get exch                  % cs b cs' csi i
          2 index exch get                       % cs b cs' csi cs'i
          ne {                                   % cs b cs'
            exch pop true exch exit
          } if
        } for                                    % cs b cs'
        pop                                      % cs b
        {
          setcolorspace
        } {
          pop
        } ifelse                                 %
      } {
        pop setcolorspace
      } ifelse
    } {
      pop setcolorspace
    } ifelse
  } {                                            % cs cs'
    pop setcolorspace
  } ifelse
  PDFR_DEBUG {
    (SetColorSpaceSafe end) =
  } if
} bind def

/ResolveColorSpaceArray  % <color_space> ResolveColorSpaceArray <color_space>
{
  //PDFR_DEBUG {
    (ResolveColorSpaceArray beg ) print dup ==
  } if
  dup 0 get /Indexed eq {
    1 //ResolveArrayElement exec
    dup dup 1 get
    dup type /arraytype eq {
      //SubstitutePDFColorSpace exec
      //ResolveColorSpaceArrayRec exec
      1 exch put
    } {
      pop pop
    } ifelse
  } if
  dup 0 get /Separation eq {
    dup dup 1 get UnPDFEscape 1 exch put
    3 //ResolveArrayElement exec
    dup 3 get //FunctionToProc exec
    2 copy 3 exch put
    pop
  } if
  dup 0 get/Pattern eq{
    dup length 1 gt {
      dup dup 1 get dup type /arraytype eq {
        ResolveColorSpaceArray
        1 index 1 3 -1 roll put
      }{
        pop
      }ifelse
    }if
  }if
  PDFR_DEBUG {
    (Construcrted color space :) =
    dup ==
  } if
  //PDFR_DEBUG {
    (ResolveColorSpaceArray end ) print dup ==
  } if
} bind def

//ResolveColorSpaceArrayRec 0 //ResolveColorSpaceArray put

/ResolveColorSpace  % <name> ResolveColorSpace <color_space>
{
  //PDFR_DEBUG {
    (ResolveColorSpace beg ) print dup =
  } if
  dup //SimpleColorSpaceNames exch known not {
    dup //PDFColorSpaces exch //knownget exec {
      exch pop
      //PDFR_DEBUG {
        (ResolveColorSpace known ) =
      } if
    } {
      dup                                               % n n
      //PDFReader /CurrentObject get /Context get /Resources get
      /ColorSpace //DoNothing //ResolveD exec
      exch //CheckColorSpace //ResolveD exec            % n cs
      dup type /arraytype eq {
        //SubstitutePDFColorSpace exec
        //ResolveColorSpaceArray exec
        dup //PDFColorSpaces 4 2 roll put               % []
      } if
    } ifelse
  } if
  //PDFR_DEBUG {
    (ResolveColorSpace end ) print dup ==
  } if
} bind def

/CheckPattern %  <key> <val> CheckPattern  <key> <val>
{
  dup /PatternType //knownget exec {
    dup 1 ne {
      mark (Resource ) 4 index ( is a shading, which can't be handled at level 2. ) //error exec
    } if
    pop
  } if
  dup /Type knownget { % /Type is optional for type 1 pattern dictionaries
    /Pattern ne {
      mark (Resource ) 4 index ( must have /Type/Pattern .) //error exec
    } if
  } if
} bind def

/PaintProc %
{ /Context get                                          % pattern_object
  //RunDelayedStream exec
} bind def

/ResolvePattern % <name> ResolvePattern <pattern>
{
  dup                                                   % n n
  % Since makepattern makes a local dictionary,
  % we cahche them in userdict, which is in local VM.
  % Assuming unique resource name through the document
  userdict /PDFR_Patterns get                           % n n d
  exch //knownget exec {                                % n p
    exch pop                                            % p
  } {                                                   % n
    dup                                                 % n n
    //PDFReader /CurrentObject get /Context get /Resources get
    /Pattern //DoNothing //ResolveD exec
    exch //CheckPattern //ResolveD exec                 % n o
    dup dup /Context exch put
    dup /Resources //DoNothing //ResolveD exec pop
    dup /PaintProc //PaintProc put
    gsave userdict /PDFR_InitialGS get setgstate
    currentglobal exch false setglobal % gs3_70 compatibility
    dup /Matrix get
    makepattern                                         % n p
    exch setglobal % gs3_70 compatibility
    grestore
    dup userdict /PDFR_Patterns get                     % n p p d
    4 2 roll                                            % p d n p
    put                                                 % p
  } ifelse
} bind def

/SetColor % Same arguments and result as for scn
{ //PDFR_DEBUG {
    (SetColor beg) =
  } if
  currentcolorspace dup type /nametype eq {
    pop setcolor
  } {
    0 get /Pattern eq {
      //ResolvePattern exec setpattern
    } {
      setcolor
    } ifelse
  } ifelse
  //PDFR_DEBUG {
    (SetColor end) =
  } if
} bind def

% ===================== Images ===============================

/ImageKeys 15 dict begin
  /BPC /BitsPerComponent def
  /CS /ColorSpace def
  /D /Decode def
  /DP /DecodeParms def
  /F /Filter def
  /H /Height def
  /IM /ImageMask def
  % /Intent is undefined - pdfwrite must take care of.
  /I /Interpolate def
  /W /Width def
currentdict end readonly def

/ImageValues 15 dict begin
  /G   /DeviceGray def
  /RGB /DeviceRGB def
  /CMYK /DeviceCMYK def
  /I   /Indexed def
  /AHx /ASCIIHexDecode def
  /A85 /ASCII85Decode def
  /LZW /LZWDecode def
  /Fl  /FlateDecode def
  /RL  /RunLengthDecode def
  /CCF /CCITTFaxDecode def
  /DCT /DCTDecode def
currentdict end readonly def

/GetColorSpaceRange
{ 2 index /ColorSpace get
  dup type /arraytype eq {
    1 get
  } if
  exch //knownget exec {
    exch pop
  } if
} bind def

/DecodeArrays 15 dict begin
  /DeviceGray { [0 1] } def
  /DeviceRGB { [0 1 0 1 0 1] } def
  /DeviceCMYK { [0 1 0 1 0 1 0 1] } def
  /Indexed {
  dup /BitsPerComponent get 1 exch bitshift 1 sub [exch 0 exch]
  } def
  /Separation { [0 1] } def
  /CIEBasedA { [0 1]  /RangeA //GetColorSpaceRange exec } def
  /CIEBasedABC { [0 1 0 1 0 1] /RangeABC //GetColorSpaceRange exec } def
currentdict end readonly def

/Substitute % <key> <dict> Substitute <key>
{ 1 index //knownget exec {
    exch pop
  } if
} bind def

/DebugImagePrinting  % <image_dict> DebugImagePrinting <image_dict>
{
  //PDFR_DEBUG {
    (Image :) =
    dup { exch //=only exec ( ) print ==
    } forall
  } if
} bind def

/CompleteImage  % <dict> CompleteImage <image_dict>
{
  dup /ColorSpace known {
    dup /ColorSpace //CheckColorSpace //ResolveD exec pop
  } if
  dup /Decode known not {
    dup /ColorSpace //knownget exec {
      dup type /arraytype eq {
        0 get
      } if
      //DecodeArrays exch get exec
    } {
      [0 1]
    } ifelse
    1 index exch /Decode exch put
  } if
  dup /ImageMatrix [2 index /Width get 0 0 5 index /Height get neg
                                        0 7 index /Height get] put % Not sure why upside down ?
  //DebugImagePrinting exec
} bind def

/CompleteInlineImage  % <dict> CompleteInlineImage <image_dict>
{
  //PDFR_DEBUG {
    (CompleteInlineImage beg) =
  } if
  dup /ImageType known not {
    dup /ImageType 1 put
  } if
  dup length dict exch {                            % d key val
    exch //ImageKeys //Substitute exec
    dup /Filter eq {
      exch //ImageValues //Substitute exec exch
    } if
    dup /ColorSpace eq {
      exch
      dup //ImageValues exch //knownget exec {
        exch pop
      } {
        //ResolveColorSpace exec
      } ifelse
      exch
    } if
    exch
    2 index 3 1 roll put
  } forall
  //CompleteImage exec
  dup /DataSource 2 copy get                        % d d /n f
  2 index //AppendFilters exec put
  //PDFR_DEBUG {
    (CompleteInlineImage end) =
  } if
} bind def

/CompleteOutlineImage  % <dict> CompleteOutlineImage <image_dict>
{
  currentglobal exch dup gcheck setglobal
  //PDFR_DEBUG {
    (CompleteOutlineImage beg) =
  } if
  % todo: ResetStreamReader if DataSource already exists.
  dup dup //MakeStreamReader exec /DataSource exch put
  dup /ImageType known not {
    //CompleteImage exec
    dup /ImageType 1 put
    dup /ColorSpace known {
      dup /ColorSpace //CheckColorSpace //ResolveD exec
      dup type /arraytype eq {
        //ResolveColorSpaceArray exec
        //SubstitutePDFColorSpace exec
        1 index exch /ColorSpace exch put
      } {
        pop
      } ifelse
    } if
  } if
  //PDFR_DEBUG {
    (CompleteOutlineImage end) =
  } if
  exch setglobal
} bind def

/DoImage % <image_dict> DoImage -
{
  //PDFR_DEBUG {
    (DoImage beg) =
  } if
  gsave
  dup /ColorSpace //knownget exec { setcolorspace } if
  dup /ImageMask //knownget exec not { false } if
  { imagemask } { image } ifelse
  grestore
  //PDFR_DEBUG {
    (DoImage end) =
  } if
} bind def

% ===================== Viewer State ===============

/GSave % - GSave -
{
  gsave
  //PDFReader /GraphicStateStackPointer get
  dup //GraphicStateStack exch get null eq {
    dup //GraphicStateStack exch //InitialGraphicState length dict put
  } if
  dup //GraphicStateStack exch get
  //GraphicState exch copy pop
  1 add //PDFReader exch /GraphicStateStackPointer exch put
} bind def

/GRestore % - GRestore -
{
  grestore
  //PDFReader /GraphicStateStackPointer get
  1 sub dup
  //PDFReader exch /GraphicStateStackPointer exch put
  //GraphicStateStack exch get
  //GraphicState copy pop
} bind def


% ===================== Interpret Data Streams ===============

/SetFont  % <resource_name> <size> SetFont -
{ dup //GraphicState exch /FontSize exch put
  //ResolveAndSetFont exec
  //GraphicState /FontMatrixNonHV currentfont /FontMatrix get 1 get 0 ne put
} bind def

/ShowText  % <string> ShowText -
{ //GraphicState /TextRenderingMode get 0 eq {
    //GraphicState /WordSpacing get 0
    32
    //GraphicState /CharacterSpacing get 0
    6 5 roll
    //GraphicState /FontMatrixNonHV get {
      % Use xshow to force wy in text space to be 0 (PDF1.7 5.3.3 "Text Space Details")
      %stack: wordspacing_wx wordspacing_wy space_char charspacing_wx charspacing_wy string
      [                                         % wwx wwy sp cwx cwy str [
        7 -2 roll pop				% sp cwx cwy str [ ww
        5 -2 roll pop				% sp str [ ww cw
        5 -1 roll                               % str [ ww cw sp
        {                                       % str [ ... ww cw sp c wx wy
          exch % will be removed, unless FontMatrix.xx == 0 (FontMatrixNonHV already true)
          pop					% str [ ... ww cw sp c w
          3 index add                           % str [ ... ww cw sp c w+cw
          exch 2 index eq { 3 index add } if    % str [ ... ww cw sp w+cw[+ww]
          4 1 roll                              % str [ ... w+cw[+ww] ww cw sp
        }
        currentfont /FontMatrix get 0 get 0 ne {
          1 1 index length 1 sub getinterval cvx % drop the "exch"
        } if
        5 index                                 % str [ ww cw sp {cshowproc} str
        cshow                                   % str [ widths... ww cw sp
      pop pop pop ]                             % str [widths...]
      xshow
    } {
      awidthshow
    } ifelse
  } {
    //GraphicState /CharacterSpacing get 0 eq
    //GraphicState /FontMatrixNonHV get not and
    //GraphicState /WordSpacing get 0 eq and {
      true charpath
    } {
      % Emulate with "{ charpath } cshow".
      % Not sure how it works with CID fonts.
      {                                                 % c wx wy
        exch % will be removed, unless FontMatrixNonHV && FontMatrix.xx == 0
        pop 0						% (PDF1.7 5.3.3 "Text Space Details")
        currentpoint 5 4 roll                           % wx wy x y c
        ( ) dup 0 3 index put true charpath             % wx wy x y c
        5 1 roll                                        % c wx wy x y
        moveto rmoveto                                  % c
        //GraphicState /CharacterSpacing get 0 rmoveto  % c
        32 eq {                                         %
          //GraphicState /WordSpacing get 0 rmoveto
        } if
      }
      //GraphicState /FontMatrixNonHV get dup not exch {
        pop currentfont /FontMatrix get 0 get 0 ne
      } if {
        1 1 index length 1 sub getinterval cvx
      } if
      exch cshow
    } ifelse
  } ifelse
} bind def

/ShowTextBeg  % - ShowTextBeg -
{ //GraphicState /TextRenderingMode get 0 ne {
        currentpoint newpath moveto
  } if
} bind def

/ShowTextEnd  % - ShowTextEnd -
{ //GraphicState /TextRenderingMode get
  { dup 1 eq {
      stroke exit
    } if
    dup 2 eq {
      gsave fill grestore stroke exit
    } if
    dup 3 eq {
      currentpoint newpath moveto
    } if
    dup 4 eq {
      gsave fill grestore clip exit
    } if
    dup 5 eq {
      gsave stroke grestore clip exit
    } if
    dup 6 eq {
      gsave fill grestore gsave stroke grestore fill exit
    } if
    dup 7 eq {
      clip exit
    } if
    exit
  } loop
  pop
} bind def

/ShowTextWithGlyphPositioning % <array> ShowTextWithGlyphPositioning -
{ //ShowTextBeg exec
  { dup type /stringtype eq {
      //ShowText exec
    } {
      neg 1000 div //GraphicState /FontSize get mul 0 rmoveto
    } ifelse
  } forall
  //ShowTextEnd exec
} bind def

/CheckFont % key val CheckFont key val
{ dup /Type get /ExtGState ne {
    mark (Resource ) 3 index ( must have /Type/ExtGState.) //error exec
  } if
} bind def

/SetTransfer % <operand> SetTransfer -
{
  //PDFR_DEBUG { (SetTransfer beg ) print count = } if
  dup type /arraytype eq 1 index xcheck not and {
    0 4 getinterval aload pop
    setcolortransfer
  } {
    settransfer
  } ifelse
  //PDFR_DEBUG { (SetTransfer end ) print count = } if
} bind def

/CheckExtGState % <id> <obj> CheckExtGState <id> <obj>
{ dup /Type get /ExtGState ne {
    mark (Resource ) 3 index ( must have /Type/ExtGState.) //error exec
  } if
} bind def

/CheckHalftone % <id> <obj> CheckHalftone <id> <obj>
{ dup /HalftoneType known not {
    mark (Resource ) 3 index ( must have /HalftoneType.) //error exec
  } if
} bind def

/ResolveFunction % <dict> <name> ResolveFunction <dict> <proc>
{
  //PDFR_DEBUG { (ResolveFunction beg ) print dup = count = } if
  2 copy get //IsObjRef exec {
    2 copy //DoNothing //ResolveD exec
    3 copy put pop
  } if
  2 copy get dup type /arraytype eq exch xcheck and not {
    2 copy get
    dup type /arraytype eq 1 index xcheck not and {
      dup length 1 sub -1 0 {
        2 copy //DoNothing ResolveA
        dup /Identity eq {
          pop 2 copy {} put
        } {
          //FunctionToProc exec
          3 copy put pop
        } ifelse
        pop
      } for
    } {
      dup /Default eq {
        % Leave it. ExtGState methods will resolve.
      } {
        dup /Identity eq {
          pop {}
        } { dup type /nametype eq {
            //spotfunctions exch get
          } {
            //FunctionToProc exec
          } ifelse
        } ifelse
      } ifelse
    } ifelse
    3 copy put
    exch pop
  } {
    1 index exch get
  } ifelse
  //PDFR_DEBUG { (ResolveFunction end ) print dup == count = } if
} bind def

/ResolveFunctionSafe % <dict> <name> ResolveFunctionSafe <dict>
{ 2 copy known {
  //ResolveFunction exec
  } if
  pop
} bind def

/CreateHalftoneThresholds  % <halftone_dict> CreateHalftoneThresholds <halftone_dict>
{
  dup /Thresholds known not {
    dup /HalftoneType get 10 eq {
      dup dup //MakeStreamReader exec
      /Thresholds exch put
    } if
    dup /HalftoneType get dup 3 eq exch 6 eq or {
      dup dup //MakeStreamReader exec
      //BlockBuffer readstring pop
      dup length
      dup 0 eq {
        mark (Could not read Thresholds) //error exec
      } if
      string copy /Thresholds exch put
      dup /HalftoneType 3 put % replace Type 6 with Type 3.
    } if
  } if
} bind def


/SetExtGState % <name> SetExtGState -
{
  //PDFReader /CurrentObject get /Context get /Resources get
  /ExtGState //DoNothing //ResolveD exec
  exch //CheckExtGState //ResolveD exec         % s gs
  dup /LW //knownget exec {
    setlinewidth
  } if
  dup /LC //knownget exec {
    setlinecap
  } if
  dup /LJ //knownget exec {
    setlinejoin
  } if
  dup /ML //knownget exec {
    setmeterlimit
  } if
  dup /D //knownget exec {
    setdash
  } if
  dup /RI //knownget exec {
    % Ghostscript never writes it.
    mark (Unimplemented ExtGState.RI) //error exec
  } if
  dup /OP //knownget exec {
    % pdfwrite must take care of stroking/filling
    setoverprint
  } if
  dup /op //knownget exec {
    setoverprint
  } if
  dup /OPM //knownget exec {
    % pdfwrite must take care of.
    mark (Unimplemented ExtGState.OPM) //error exec
  } if
  dup /Font //knownget exec {
    % Ghostscript never writes it.
    mark (Unimplemented ExtGState.Font) //error exec
  } if
  dup /BG known {
    /BG //ResolveFunction exec
    setblackgeneration
  } if
  dup /BG2 known {
    /BG2 //ResolveFunction exec
    dup /Default eq {
      //InitialExtGState /BG2 get
    } if
    setblackgeneration
  } if
  dup /UCR known {
    /UCR //ResolveFunction exec
    setundercolorremoval
  } if
  dup /UCR2 known {
    /UCR2 //ResolveFunction exec
    dup /Default eq {
      //InitialExtGState /UCR2 get
    } if
    setundercolorremoval
  } if
  dup /TR known {
    /TR //ResolveFunction exec
    //SetTransfer exec
  } if
  dup /TR2 known {
    /TR2 //ResolveFunction exec
    dup /Default eq {
      pop //InitialExtGState /TR2 get
      aload pop setcolortransfer
    } {
      //SetTransfer exec
    } ifelse
  } if
  dup /HT //knownget exec {
    dup /Default eq {
      pop //InitialExtGState /HT get
      sethalftone
    } {
      //PDFR_DEBUG { (Ht beg) = } if
      pop dup /HT //CheckHalftone //ResolveD exec
      /SpotFunction //ResolveFunctionSafe exec
      /TransferFunction //ResolveFunctionSafe exec
      null exch
      dup /HalftoneType get dup 5 eq exch dup 4 eq exch 2 eq or or {
        dup {                             % null h n v
          dup //IsObjRef exec {
            pop
            1 index exch //CheckHalftone ResolveD
          } if
          dup type /dicttype eq {
            dup /SpotFunction //ResolveFunctionSafe exec
            /TransferFunction //ResolveFunctionSafe exec
            //CreateHalftoneThresholds exec
            dup /HalftoneType get 5 gt {    % null h n v
              4 3 roll pop
              dup 4 1 roll
            } if
          } if
          pop pop
        } forall
      } if
      //CreateHalftoneThresholds exec
      //PDFR_DEBUG {
        (HT:)=
        dup {
          1 index /Default eq {
            (Default <<)=
              exch pop
              { exch = == } forall
            (>>)=
          } {
            exch = ==
          } ifelse
        } forall
        (HT end)= flush
      } if
      exch dup null ne {
        (Warning: Ignoring a halftone with a Level 3 component halftone Type ) print dup /HalftoneType get =
        pop pop
      } {
        pop
        dup /HalftoneType get 5 gt {
          (Warning: Ignoring a Level 3 halftone Type ) print dup /HalftoneType get =
          pop
        } {
          sethalftone
        } ifelse
      } ifelse
      //PDFR_DEBUG { (HT set)= flush } if
    } ifelse
  } if
  dup /FL //knownget exec {
    setflattness
  } if
  dup /SM //knownget exec {
    setsmoothness
  } if
  dup /SA //knownget exec {
    setstrokeadjust
  } if
  dup /BM //knownget exec {
    % pdfwrite must take care of.
    mark (Unimplemented ExtGState.BM) //error exec
  } if
  dup /SMask //knownget exec {
    % pdfwrite must take care of.
    mark (Unimplemented ExtGState.SMask) //error exec
  } if
  dup /CA //knownget exec {
    % pdfwrite must take care of.
    mark (Unimplemented ExtGState.CA) //error exec
  } if
  dup /ca //knownget exec {
    % pdfwrite must take care of.
    mark (Unimplemented ExtGState.ca) //error exec
  } if
  dup /AIS //knownget exec {
    % pdfwrite must take care of.
    mark (Unimplemented ExtGState.AIS) //error exec
  } if
  dup /TK //knownget exec {
    % pdfwrite must take care of.
    mark (Unimplemented ExtGState.TK) //error exec
  } if
  pop
} bind def

/CheckXObject  % <id> <obj> CheckHalftone <id> <obj>
{ dup /Subtype get dup /Image ne exch dup /Form ne exch /PS ne and and {
    mark (Resource ) 3 index ( must have /Subtype /Image or /Form or /PS.) //error exec
  } if
} bind def

/DoXObject % <name> DoXObject -
{
  //PDFReader /CurrentObject get /Context get /Resources get
  /XObject //DoNothing //ResolveD exec
  exch //CheckXObject //ResolveD exec
  dup /Subtype get
  dup /Image eq {
    pop
    //CompleteOutlineImage exec
    //DoImage exec
  } {
    dup /PS eq {
      PDFR_DEBUG {
        (Executing a PS Xobject) =
      } if
      pop
      //RunDelayedStream exec
    } {
      dup /Form eq {
        pop
        PDFR_DEBUG {
          (Executing a Form XObject) =
        } if
        //PDFReader /CurrentObject get exch
        dup //PDFReader exch << exch /Context exch >> /CurrentObject exch put
        dup /Matrix get concat
        dup /BBox get aload pop exch 3 index sub exch 2 index sub rectclip
        //RunDelayedStream exec
        //PDFReader exch /CurrentObject exch put
      } {
        mark exch (unimplemented XObject type ) exch //error exec
      } ifelse
    } ifelse
  } ifelse
} bind def

/Operators 50 dict begin
  /q { //GSave exec } bind def
  /Q { //GRestore exec } bind def
  /cm { //TempMatrix astore concat } bind def
  /i { 1 .min setflat } bind def
  /J /setlinecap load def
  /d /setdash load def
  /j /setlinejoin load def
  /w /setlinewidth load def
  /M /setmiterlimit load def
  /gs { SetExtGState } bind def

  /g /setgray load def
  /rg /setrgbcolor load def
  /k /setcmykcolor load def
  /cs { //ResolveColorSpace exec //SetColorSpaceSafe exec
      } bind def
  /sc /setcolor load def
  /scn { //SetColor exec } bind def
  /G /setgray load def
  /RG /setrgbcolor load def
  /K /setcmykcolor load def
  /CS //cs def
  /ri { SetColorRenderingIntent } bind def
  /SC /setcolor load def
  /SCN { //SetColor exec } bind def

  /m /moveto load def
  /l /lineto load def
  /c /curveto load def
  /v { currentpoint 6 2 roll curveto } bind def
  /y { 2 copy curveto } bind def
  /re {
    4 2 roll moveto  exch dup 0 rlineto  0 3 -1 roll rlineto  neg 0 rlineto
    closepath
  } def
  /h /closepath load def
  /n /newpath load def
  /S /stroke load def
  /s { closepath stroke } bind def
  /f /fill load def
  /f* /eofill load def
  /B { gsave fill grestore stroke } bind def
  /b { closepath gsave fill grestore stroke } bind def
  /B* { gsave eofill grestore stroke } bind def
  /b* { closepath gsave eofill grestore stroke } bind def
  /W /clip load def
  /W* /eoclip load def
  /sh { % Reserved for ps3write.
        ResolveShading
        dup /Background known {
          gsave
          dup /ColorSpace get setcolorspace
          dup /Background get aload pop setcolor
          pathbbox               % x0 y0 x1 y1
          2 index sub exch 3 index sub exch
          rectfill
          grestore
        } if
        shfill
      } bind def

  /Do { //DoXObject exec } bind def

  /BI { currentglobal false setglobal << } bind def
  /ID { >>
        dup /DataSource currentfile
        % HACK BEG
        % This hack provides a compatibility to HP LaserJet 1320,
        % which sometimes closes the underlying stream when EOD
        % is reached in the ASCII85Decode filter.
        % This portion is not required by the Postscript language definition.
        2 index /F //knownget exec {
          /A85 eq {
            0 (~>) /SubFileDecode filter
          } if
        } if
        % HACK END
        put
        //CompleteInlineImage exec
        exch setglobal
        //DoImage exec
      } bind def
  /EI {} bind def

  /BT { gsave //GraphicState /InitialTextMatrix get currentmatrix pop } bind def
  /ET { grestore } bind def
  /Tc { //GraphicState exch /CharacterSpacing exch put } bind def
  /TL { //GraphicState exch /TextLeading exch put } bind def
  /Tr { //GraphicState exch /TextRenderingMode exch put } bind def
  /Ts {  % Ghostscript never generates it.
        mark (Unimplemented SetTextRise) //error exec
      } bind def
  /Tw { //GraphicState exch /WordSpacing exch put } bind def
  /Tz { % Ghostscript never generates it.
            mark (Unimplemented SetHorizontalTextScaling) //error exec
      } bind def
  /Td { translate 0 0 moveto } bind def
  /TD { dup neg //TL exec //Td exec } bind def
  /Tm { //GraphicState /InitialTextMatrix get setmatrix
        //TempMatrix astore concat
        0 0 moveto } bind def
  /T* { 0 //GraphicState /TextLeading get neg //Td exec } bind def
  /Tj { //ShowTextBeg exec  //ShowText exec  //ShowTextEnd exec } bind def
  /'  { //T* exec  //ShowText exec  //ShowTextEnd exec } bind def
  /"  { 3 2 roll //Tw exec exch //Tc exec //' exec} bind def
  /TJ //ShowTextWithGlyphPositioning def
  /Tf //SetFont def

  /d0 /setcharwidth load def
  /d1 /setcachedevice load def

  /BDC { pop pop } bind def
  /BMC { pop } bind def
  /EMC {  } bind def
  /BX { BeginCompatibilitySection } bind def
  /EX { EndCompatibilitySection } bind def
  /DP { DefineMarkedContentPointWithPropertyList } bind def
  /MP { DefineMarkedContentPoint } bind def
  /PS { cvx exec } bind def
currentdict end def

//PDFR_STREAM {
  % Rebind operators with a debug tracing.
  //Operators length dict begin
  //Operators {                                 % n p
    exch dup                                    % p n n
    [ exch //=only /exec load                   % p n [ n =only exec
      ( ) /print load                           % p n [ n =only exec () print
      8 7 roll                                  % n [ n =only exec () print p
      dup type /arraytype eq {
        /exec load                              % n [ n =only exec () print p exec
      } if
      ( ) /print load
    ] cvx                                       % n {}
    def
  } forall
  currentdict end /Operators exch def
} if

% Functions for handling Ghostscript library files that define encodings.

/.registerencoding
{ pop pop
} bind def

/.defineencoding
{ def
} bind def

/.findencoding
{ load
} bind def


% Leaving the procset on the dictionary stack to provide
% definitions of obj, endobj, stream, endstream, R, xref.
%%EndPrologue
